LCOV - code coverage report
Current view: top level - plugins/lvm - lvm.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 74.1 % 1435 1063
Test Date: 2026-01-26 13:19:28 Functions: 80.9 % 94 76
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2014  Red Hat, Inc.
       3              :  *
       4              :  * This library is free software; you can redistribute it and/or
       5              :  * modify it under the terms of the GNU Lesser General Public
       6              :  * License as published by the Free Software Foundation; either
       7              :  * version 2.1 of the License, or (at your option) any later version.
       8              :  *
       9              :  * This library is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12              :  * Lesser General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU Lesser General Public
      15              :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      16              :  *
      17              :  * Author: Vratislav Podzimek <vpodzime@redhat.com>
      18              :  */
      19              : 
      20              : #include <glib.h>
      21              : #include <math.h>
      22              : #include <string.h>
      23              : #include <unistd.h>
      24              : #include <blockdev/utils.h>
      25              : #include <libdevmapper.h>
      26              : 
      27              : #include "lvm.h"
      28              : #include "lvm-private.h"
      29              : #include "check_deps.h"
      30              : #include "dm_logging.h"
      31              : #include "vdo_stats.h"
      32              : 
      33              : /**
      34              :  * SECTION: lvm
      35              :  * @short_description: plugin for operations with LVM
      36              :  * @title: LVM
      37              :  * @include: lvm.h
      38              :  *
      39              :  * A plugin for operations with LVM. All sizes passed in/out to/from
      40              :  * the functions are in bytes.
      41              :  */
      42              : 
      43              : /**
      44              :  * bd_lvm_error_quark: (skip)
      45              :  */
      46            0 : GQuark bd_lvm_error_quark (void)
      47              : {
      48            0 :     return g_quark_from_static_string ("g-bd-lvm-error-quark");
      49              : }
      50              : 
      51            0 : BDLVMPVdata* bd_lvm_pvdata_copy (BDLVMPVdata *data) {
      52            0 :     if (data == NULL)
      53            0 :         return NULL;
      54              : 
      55            0 :     BDLVMPVdata *new_data = g_new0 (BDLVMPVdata, 1);
      56              : 
      57            0 :     new_data->pv_name = g_strdup (data->pv_name);
      58            0 :     new_data->pv_uuid = g_strdup (data->pv_uuid);
      59            0 :     new_data->pv_free = data->pv_free;
      60            0 :     new_data->pv_size = data->pv_size;
      61            0 :     new_data->pe_start = data->pe_start;
      62            0 :     new_data->vg_name = g_strdup (data->vg_name);
      63            0 :     new_data->vg_uuid = g_strdup (data->vg_uuid);
      64            0 :     new_data->vg_size = data->vg_size;
      65            0 :     new_data->vg_free = data->vg_free;
      66            0 :     new_data->vg_extent_size = data->vg_extent_size;
      67            0 :     new_data->vg_extent_count = data->vg_extent_count;
      68            0 :     new_data->vg_free_count = data->vg_free_count;
      69            0 :     new_data->vg_pv_count = data->vg_pv_count;
      70            0 :     new_data->pv_tags = g_strdupv (data->pv_tags);
      71            0 :     new_data->missing = data->missing;
      72              : 
      73            0 :     return new_data;
      74              : }
      75              : 
      76            0 : void bd_lvm_pvdata_free (BDLVMPVdata *data) {
      77            0 :     if (data == NULL)
      78            0 :         return;
      79              : 
      80            0 :     g_free (data->pv_name);
      81            0 :     g_free (data->pv_uuid);
      82            0 :     g_free (data->vg_name);
      83            0 :     g_free (data->vg_uuid);
      84            0 :     g_strfreev (data->pv_tags);
      85            0 :     g_free (data);
      86              : }
      87              : 
      88            0 : BDLVMVGdata* bd_lvm_vgdata_copy (BDLVMVGdata *data) {
      89            0 :     if (data == NULL)
      90            0 :         return NULL;
      91              : 
      92            0 :     BDLVMVGdata *new_data = g_new0 (BDLVMVGdata, 1);
      93              : 
      94            0 :     new_data->name = g_strdup (data->name);
      95            0 :     new_data->uuid = g_strdup (data->uuid);
      96            0 :     new_data->size = data->size;
      97            0 :     new_data->free = data->free;
      98            0 :     new_data->extent_size = data->extent_size;
      99            0 :     new_data->extent_count = data->extent_count;
     100            0 :     new_data->free_count = data->free_count;
     101            0 :     new_data->pv_count = data->pv_count;
     102            0 :     new_data->vg_tags = g_strdupv (data->vg_tags);
     103            0 :     return new_data;
     104              : }
     105              : 
     106            0 : void bd_lvm_vgdata_free (BDLVMVGdata *data) {
     107            0 :     if (data == NULL)
     108            0 :         return;
     109              : 
     110            0 :     g_free (data->name);
     111            0 :     g_free (data->uuid);
     112            0 :     g_strfreev (data->vg_tags);
     113            0 :     g_free (data);
     114              : }
     115              : 
     116            0 : BDLVMSEGdata* bd_lvm_segdata_copy (BDLVMSEGdata *data) {
     117            0 :     if (data == NULL)
     118            0 :         return NULL;
     119              : 
     120            0 :     BDLVMSEGdata *new_data = g_new0 (BDLVMSEGdata, 1);
     121              : 
     122            0 :     new_data->size_pe = data->size_pe;
     123            0 :     new_data->pv_start_pe = data->pv_start_pe;
     124            0 :     new_data->pvdev = g_strdup (data->pvdev);
     125            0 :     return new_data;
     126              : }
     127              : 
     128            0 : void bd_lvm_segdata_free (BDLVMSEGdata *data) {
     129            0 :     if (data == NULL)
     130            0 :         return;
     131              : 
     132            0 :     g_free (data->pvdev);
     133            0 :     g_free (data);
     134              : }
     135              : 
     136            0 : static BDLVMSEGdata **copy_segs (BDLVMSEGdata **segs) {
     137              :     int len;
     138              :     BDLVMSEGdata **new_segs;
     139              : 
     140            0 :     if (segs == NULL)
     141            0 :        return NULL;
     142              : 
     143            0 :     for (len = 0; segs[len]; len++)
     144              :         ;
     145              : 
     146            0 :     new_segs = g_new0 (BDLVMSEGdata *, len+1);
     147            0 :     for (int i = 0; i < len; i++)
     148            0 :         new_segs[i] = bd_lvm_segdata_copy (segs[i]);
     149              : 
     150            0 :     return new_segs;
     151              : }
     152              : 
     153            0 : static void free_segs (BDLVMSEGdata **segs) {
     154            0 :     if (segs == NULL)
     155            0 :        return;
     156              : 
     157            0 :     for (int i = 0; segs[i]; i++)
     158            0 :         bd_lvm_segdata_free (segs[i]);
     159            0 :     (g_free) (segs);
     160              : }
     161              : 
     162            0 : BDLVMLVdata* bd_lvm_lvdata_copy (BDLVMLVdata *data) {
     163            0 :     if (data == NULL)
     164            0 :         return NULL;
     165              : 
     166            0 :     BDLVMLVdata *new_data = g_new0 (BDLVMLVdata, 1);
     167              : 
     168            0 :     new_data->lv_name = g_strdup (data->lv_name);
     169            0 :     new_data->vg_name = g_strdup (data->vg_name);
     170            0 :     new_data->uuid = g_strdup (data->uuid);
     171            0 :     new_data->size = data->size;
     172            0 :     new_data->attr = g_strdup (data->attr);
     173            0 :     new_data->segtype = g_strdup (data->segtype);
     174            0 :     new_data->origin = g_strdup (data->origin);
     175            0 :     new_data->pool_lv = g_strdup (data->pool_lv);
     176            0 :     new_data->data_lv = g_strdup (data->data_lv);
     177            0 :     new_data->metadata_lv = g_strdup (data->metadata_lv);
     178            0 :     new_data->roles = g_strdup (data->roles);
     179            0 :     new_data->move_pv = g_strdup (data->move_pv);
     180            0 :     new_data->data_percent = data->data_percent;
     181            0 :     new_data->metadata_percent = data->metadata_percent;
     182            0 :     new_data->copy_percent = data->copy_percent;
     183            0 :     new_data->lv_tags = g_strdupv (data->lv_tags);
     184            0 :     new_data->data_lvs = g_strdupv (data->data_lvs);
     185            0 :     new_data->metadata_lvs = g_strdupv (data->metadata_lvs);
     186            0 :     new_data->segs = copy_segs (data->segs);
     187            0 :     return new_data;
     188              : }
     189              : 
     190            0 : void bd_lvm_lvdata_free (BDLVMLVdata *data) {
     191            0 :     if (data == NULL)
     192            0 :         return;
     193              : 
     194            0 :     g_free (data->lv_name);
     195            0 :     g_free (data->vg_name);
     196            0 :     g_free (data->uuid);
     197            0 :     g_free (data->attr);
     198            0 :     g_free (data->segtype);
     199            0 :     g_free (data->origin);
     200            0 :     g_free (data->pool_lv);
     201            0 :     g_free (data->data_lv);
     202            0 :     g_free (data->metadata_lv);
     203            0 :     g_free (data->roles);
     204            0 :     g_free (data->move_pv);
     205            0 :     g_strfreev (data->lv_tags);
     206            0 :     g_strfreev (data->data_lvs);
     207            0 :     g_strfreev (data->metadata_lvs);
     208            0 :     free_segs (data->segs);
     209            0 :     g_free (data);
     210              : }
     211              : 
     212            0 : BDLVMVDOPooldata* bd_lvm_vdopooldata_copy (BDLVMVDOPooldata *data) {
     213            0 :     if (data == NULL)
     214            0 :         return NULL;
     215              : 
     216            0 :     BDLVMVDOPooldata *new_data = g_new0 (BDLVMVDOPooldata, 1);
     217              : 
     218            0 :     new_data->operating_mode = data->operating_mode;
     219            0 :     new_data->compression_state = data->compression_state;
     220            0 :     new_data->index_state = data->index_state;
     221            0 :     new_data->write_policy = data->write_policy;
     222            0 :     new_data->used_size = data->used_size;
     223            0 :     new_data->saving_percent = data->saving_percent;
     224            0 :     new_data->index_memory_size = data->index_memory_size;
     225            0 :     new_data->deduplication = data->deduplication;
     226            0 :     new_data->compression = data->compression;
     227            0 :     return new_data;
     228              : }
     229              : 
     230            0 : void bd_lvm_vdopooldata_free (BDLVMVDOPooldata *data) {
     231            0 :     if (data == NULL)
     232            0 :         return;
     233              : 
     234            0 :     g_free (data);
     235              : }
     236              : 
     237            0 : BDLVMCacheStats* bd_lvm_cache_stats_copy (BDLVMCacheStats *data) {
     238            0 :     if (data == NULL)
     239            0 :         return NULL;
     240              : 
     241            0 :     BDLVMCacheStats *new = g_new0 (BDLVMCacheStats, 1);
     242              : 
     243            0 :     new->block_size = data->block_size;
     244            0 :     new->cache_size = data->cache_size;
     245            0 :     new->cache_used = data->cache_used;
     246            0 :     new->md_block_size = data->md_block_size;
     247            0 :     new->md_size = data->md_size;
     248            0 :     new->md_used = data->md_used;
     249            0 :     new->read_hits = data->read_hits;
     250            0 :     new->read_misses = data->read_misses;
     251            0 :     new->write_hits = data->write_hits;
     252            0 :     new->write_misses = data->write_misses;
     253            0 :     new->mode = data->mode;
     254              : 
     255            0 :     return new;
     256              : }
     257              : 
     258            0 : void bd_lvm_cache_stats_free (BDLVMCacheStats *data) {
     259            0 :     g_free (data);
     260            0 : }
     261              : 
     262              : 
     263              : static volatile guint avail_deps = 0;
     264              : static volatile guint avail_features = 0;
     265              : static volatile guint avail_module_deps = 0;
     266              : static GMutex deps_check_lock;
     267              : 
     268              : #define DEPS_LVM 0
     269              : #define DEPS_LVM_MASK (1 << DEPS_LVM)
     270              : #define DEPS_LVMDEVICES 1
     271              : #define DEPS_LVMDEVICES_MASK (1 << DEPS_LVMDEVICES)
     272              : #define DEPS_LVMCONFIG 2
     273              : #define DEPS_LVMCONFIG_MASK (1 << DEPS_LVMCONFIG)
     274              : #define DEPS_LAST 3
     275              : 
     276              : static const UtilDep deps[DEPS_LAST] = {
     277              :     {"lvm", LVM_MIN_VERSION, "version", "LVM version:\\s+([\\d\\.]+)"},
     278              :     {"lvmdevices", NULL, NULL, NULL},
     279              :     {"lvmconfig", "2.03.17", "--version", "LVM version:\\s+([\\d\\.]+)"},
     280              : };
     281              : 
     282              : #define FEATURES_VDO 0
     283              : #define FEATURES_VDO_MASK (1 << FEATURES_VDO)
     284              : #define FEATURES_WRITECACHE 0
     285              : #define FEATURES_WRITECACHE_MASK (1 << FEATURES_WRITECACHE)
     286              : #define FEATURES_LAST 2
     287              : 
     288              : static const UtilFeatureDep features[FEATURES_LAST] = {
     289              :     {"lvm", "vdo", "segtypes", NULL},
     290              :     {"lvm", "writecache", "segtypes", NULL},
     291              : };
     292              : 
     293              : #define MODULE_DEPS_VDO 0
     294              : #define MODULE_DEPS_VDO_MASK (1 << MODULE_DEPS_VDO)
     295              : #define MODULE_DEPS_LAST 1
     296              : 
     297              : static const gchar*const module_deps[MODULE_DEPS_LAST] = { "dm-vdo" };
     298              : 
     299              : 
     300              : /**
     301              :  * bd_lvm_init:
     302              :  *
     303              :  * Initializes the plugin. **This function is called automatically by the
     304              :  * library's initialization functions.**
     305              :  *
     306              :  */
     307           26 : gboolean bd_lvm_init (void) {
     308           26 :     dm_log_with_errno_init ((dm_log_with_errno_fn) redirect_dm_log);
     309              : #ifdef DEBUG
     310              :     dm_log_init_verbose (LOG_DEBUG);
     311              : #else
     312           26 :     dm_log_init_verbose (LOG_INFO);
     313              : #endif
     314              : 
     315           26 :     return TRUE;
     316              : };
     317              : 
     318              : /**
     319              :  * bd_lvm_close:
     320              :  *
     321              :  * Cleans up after the plugin. **This function is called automatically by the
     322              :  * library's functions that unload it.**
     323              :  *
     324              :  */
     325           26 : void bd_lvm_close (void) {
     326           26 :     dm_log_with_errno_init (NULL);
     327           26 :     dm_log_init_verbose (0);
     328           26 : }
     329              : 
     330              : /**
     331              :  * bd_lvm_is_tech_avail:
     332              :  * @tech: the queried tech
     333              :  * @mode: a bit mask of queried modes of operation (#BDLVMTechMode) for @tech
     334              :  * @error: (out) (optional): place to store error (details about why the @tech-@mode combination is not available)
     335              :  *
     336              :  * Returns: whether the @tech-@mode combination is available -- supported by the
     337              :  *          plugin implementation and having all the runtime dependencies available
     338              :  */
     339          166 : gboolean bd_lvm_is_tech_avail (BDLVMTech tech, guint64 mode, GError **error) {
     340          166 :     switch (tech) {
     341            1 :     case BD_LVM_TECH_THIN_CALCS:
     342            1 :         if (mode & ~BD_LVM_TECH_MODE_QUERY) {
     343            1 :             g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_TECH_UNAVAIL,
     344              :                          "Only 'query' supported for thin calculations");
     345            1 :             return FALSE;
     346              :         } else
     347            0 :             return TRUE;
     348            0 :     case BD_LVM_TECH_CALCS:
     349            0 :         if (mode & ~BD_LVM_TECH_MODE_QUERY) {
     350            0 :             g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_TECH_UNAVAIL,
     351              :                          "Only 'query' supported for calculations");
     352            0 :             return FALSE;
     353              :         } else
     354            0 :             return TRUE;
     355            0 :     case BD_LVM_TECH_VDO:
     356            0 :             return check_features (&avail_features, FEATURES_VDO_MASK, features, FEATURES_LAST, &deps_check_lock, error) &&
     357            0 :                    check_module_deps (&avail_module_deps, MODULE_DEPS_VDO_MASK, module_deps, MODULE_DEPS_LAST, &deps_check_lock, error) &&
     358            0 :                    check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error);
     359            0 :     case BD_LVM_TECH_WRITECACHE:
     360            0 :             return check_features (&avail_features, FEATURES_WRITECACHE_MASK, features, FEATURES_LAST, &deps_check_lock, error) &&
     361            0 :                    check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error);
     362          162 :     case BD_LVM_TECH_DEVICES:
     363          162 :             return check_deps (&avail_deps, DEPS_LVMDEVICES_MASK, deps, DEPS_LAST, &deps_check_lock, error);
     364            1 :     case BD_LVM_TECH_CONFIG:
     365            1 :         return check_deps (&avail_deps, DEPS_LVMCONFIG_MASK, deps, DEPS_LAST, &deps_check_lock, error);
     366            2 :     default:
     367              :         /* everything is supported by this implementation of the plugin */
     368            2 :         return check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error);
     369              :     }
     370              : }
     371              : 
     372          557 : static gboolean call_lvm_and_report_error (const gchar **args, const BDExtraArg **extra, gboolean lock_config, GError **error) {
     373          557 :     gboolean success = FALSE;
     374          557 :     guint i = 0;
     375          557 :     guint args_length = g_strv_length ((gchar **) args);
     376          557 :     g_autofree gchar *config_arg = NULL;
     377          557 :     g_autofree gchar *devices_arg = NULL;
     378              : 
     379          557 :     if (!check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     380            0 :         return FALSE;
     381              : 
     382              :     /* don't allow global config string changes during the run */
     383          557 :     if (lock_config)
     384          549 :         g_mutex_lock (&global_config_lock);
     385              : 
     386              :     /* allocate enough space for the args plus "lvm", "--config", "--devices" and NULL */
     387          557 :     const gchar **argv = g_new0 (const gchar*, args_length + 4);
     388              : 
     389              :     /* construct argv from args with "lvm" prepended */
     390          557 :     argv[0] = "lvm";
     391         3204 :     for (i=0; i < args_length; i++)
     392         2647 :         argv[i+1] = args[i];
     393          557 :     if (global_config_str) {
     394           15 :         config_arg = g_strdup_printf ("--config=%s", global_config_str);
     395           15 :         argv[++args_length] = config_arg;
     396              :     }
     397          557 :     if (global_devices_str) {
     398            1 :         devices_arg = g_strdup_printf ("--devices=%s", global_devices_str);
     399            1 :         argv[++args_length] = devices_arg;
     400              :     }
     401          557 :     argv[++args_length] = NULL;
     402              : 
     403          557 :     success = bd_utils_exec_and_report_error (argv, extra, error);
     404          557 :     if (lock_config)
     405          549 :         g_mutex_unlock (&global_config_lock);
     406          557 :     g_free (argv);
     407              : 
     408          557 :     return success;
     409              : }
     410              : 
     411           97 : static gboolean call_lvm_and_capture_output (const gchar **args, const BDExtraArg **extra, gchar **output, GError **error) {
     412           97 :     gboolean success = FALSE;
     413           97 :     guint i = 0;
     414           97 :     guint args_length = g_strv_length ((gchar **) args);
     415           97 :     g_autofree gchar *config_arg = NULL;
     416           97 :     g_autofree gchar *devices_arg = NULL;
     417              : 
     418           97 :     if (!check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     419            0 :         return FALSE;
     420              : 
     421              :     /* don't allow global config string changes during the run */
     422           97 :     g_mutex_lock (&global_config_lock);
     423              : 
     424              :     /* allocate enough space for the args plus "lvm", "--config", "--devices" and NULL */
     425           97 :     const gchar **argv = g_new0 (const gchar*, args_length + 4);
     426              : 
     427              :     /* construct argv from args with "lvm" prepended */
     428           97 :     argv[0] = "lvm";
     429         1013 :     for (i=0; i < args_length; i++)
     430          916 :         argv[i+1] = args[i];
     431           97 :     if (global_config_str) {
     432            0 :         config_arg = g_strdup_printf ("--config=%s", global_config_str);
     433            0 :         argv[++args_length] = config_arg;
     434              :     }
     435           97 :     if (global_devices_str) {
     436            0 :         devices_arg = g_strdup_printf ("--devices=%s", global_devices_str);
     437            0 :         argv[++args_length] = devices_arg;
     438              :     }
     439           97 :     argv[++args_length] = NULL;
     440              : 
     441           97 :     success = bd_utils_exec_and_capture_output (argv, extra, output, error);
     442           97 :     g_mutex_unlock (&global_config_lock);
     443           97 :     g_free (argv);
     444              : 
     445           97 :     return success;
     446              : }
     447              : 
     448              : /**
     449              :  * parse_lvm_vars:
     450              :  * @str: string to parse
     451              :  * @num_items: (out): number of parsed items
     452              :  *
     453              :  * Returns: (transfer full): a GHashTable containing key-value items parsed from the @string
     454              :  */
     455          143 : static GHashTable* parse_lvm_vars (const gchar *str, guint *num_items) {
     456          143 :     GHashTable *table = NULL;
     457          143 :     gchar **items = NULL;
     458          143 :     gchar **item_p = NULL;
     459          143 :     gchar **key_val = NULL;
     460              : 
     461          143 :     table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
     462          143 :     *num_items = 0;
     463              : 
     464          143 :     items = g_strsplit_set (str, " \t\n", 0);
     465         2250 :     for (item_p=items; *item_p; item_p++) {
     466         2107 :         key_val = g_strsplit (*item_p, "=", 2);
     467         2107 :         if (g_strv_length (key_val) == 2) {
     468              :             /* we only want to process valid lines (with the '=' character) */
     469         1867 :             g_hash_table_insert (table, key_val[0], key_val[1]);
     470         1867 :             g_free (key_val);
     471         1867 :             (*num_items)++;
     472              :         } else
     473              :             /* invalid line, just free key_val */
     474          240 :             g_strfreev (key_val);
     475              :     }
     476              : 
     477          143 :     g_strfreev (items);
     478          143 :     return table;
     479              : }
     480              : 
     481           15 : static BDLVMPVdata* get_pv_data_from_table (GHashTable *table, gboolean free_table) {
     482           15 :     BDLVMPVdata *data = g_new0 (BDLVMPVdata, 1);
     483           15 :     gchar *value = NULL;
     484              : 
     485           15 :     data->pv_name = g_strdup ((gchar*) g_hash_table_lookup (table, "LVM2_PV_NAME"));
     486           15 :     data->pv_uuid = g_strdup ((gchar*) g_hash_table_lookup (table, "LVM2_PV_UUID"));
     487              : 
     488           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_PV_FREE");
     489           15 :     if (value)
     490           15 :         data->pv_free = g_ascii_strtoull (value, NULL, 0);
     491              :     else
     492            0 :         data->pv_free = 0;
     493              : 
     494           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_PV_SIZE");
     495           15 :     if (value)
     496           15 :         data->pv_size = g_ascii_strtoull (value, NULL, 0);
     497              :     else
     498            0 :         data->pv_size = 0;
     499              : 
     500           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_PE_START");
     501           15 :     if (value)
     502           15 :         data->pe_start = g_ascii_strtoull (value, NULL, 0);
     503              :     else
     504            0 :         data->pe_start = 0;
     505              : 
     506           15 :     data->vg_name = g_strdup ((gchar*) g_hash_table_lookup (table, "LVM2_VG_NAME"));
     507           15 :     data->vg_uuid = g_strdup ((gchar*) g_hash_table_lookup (table, "LVM2_VG_UUID"));
     508              : 
     509           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_SIZE");
     510           15 :     if (value)
     511           15 :         data->vg_size = g_ascii_strtoull (value, NULL, 0);
     512              :     else
     513            0 :         data->vg_size = 0;
     514              : 
     515           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_FREE");
     516           15 :     if (value)
     517           15 :         data->vg_free = g_ascii_strtoull (value, NULL, 0);
     518              :     else
     519            0 :         data->vg_free = 0;
     520              : 
     521           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_EXTENT_SIZE");
     522           15 :     if (value)
     523           15 :         data->vg_extent_size = g_ascii_strtoull (value, NULL, 0);
     524              :     else
     525            0 :         data->vg_extent_size = 0;
     526              : 
     527           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_EXTENT_COUNT");
     528           15 :     if (value)
     529           15 :         data->vg_extent_count = g_ascii_strtoull (value, NULL, 0);
     530              :     else
     531            0 :         data->vg_extent_count = 0;
     532              : 
     533           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_FREE_COUNT");
     534           15 :     if (value)
     535           15 :         data->vg_free_count = g_ascii_strtoull (value, NULL, 0);
     536              :     else
     537            0 :         data->vg_free_count = 0;
     538              : 
     539           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_PV_COUNT");
     540           15 :     if (value)
     541           15 :         data->vg_pv_count = g_ascii_strtoull (value, NULL, 0);
     542              :     else
     543            0 :         data->vg_pv_count = 0;
     544              : 
     545           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_PV_TAGS");
     546           15 :     if (value)
     547           15 :         data->pv_tags = g_strsplit (value, ",", -1);
     548              :     else
     549            0 :         data->pv_tags = NULL;
     550              : 
     551           15 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_PV_MISSING");
     552           15 :     data->missing = (g_strcmp0 (value, "missing") == 0);
     553              : 
     554           15 :     if (free_table)
     555           15 :         g_hash_table_destroy (table);
     556              : 
     557           15 :     return data;
     558              : }
     559              : 
     560            7 : static BDLVMVGdata* get_vg_data_from_table (GHashTable *table, gboolean free_table) {
     561            7 :     BDLVMVGdata *data = g_new0 (BDLVMVGdata, 1);
     562            7 :     gchar *value = NULL;
     563              : 
     564            7 :     data->name = g_strdup (g_hash_table_lookup (table, "LVM2_VG_NAME"));
     565            7 :     data->uuid = g_strdup (g_hash_table_lookup (table, "LVM2_VG_UUID"));
     566              : 
     567            7 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_SIZE");
     568            7 :     if (value)
     569            7 :         data->size = g_ascii_strtoull (value, NULL, 0);
     570              :     else
     571            0 :         data->size = 0;
     572              : 
     573            7 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_FREE");
     574            7 :     if (value)
     575            7 :         data->free = g_ascii_strtoull (value, NULL, 0);
     576              :     else
     577            0 :         data->free= 0;
     578              : 
     579            7 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_EXTENT_SIZE");
     580            7 :     if (value)
     581            7 :         data->extent_size = g_ascii_strtoull (value, NULL, 0);
     582              :     else
     583            0 :         data->extent_size = 0;
     584              : 
     585            7 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_EXTENT_COUNT");
     586            7 :     if (value)
     587            7 :         data->extent_count = g_ascii_strtoull (value, NULL, 0);
     588              :     else
     589            0 :         data->extent_count = 0;
     590              : 
     591            7 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_FREE_COUNT");
     592            7 :     if (value)
     593            7 :         data->free_count = g_ascii_strtoull (value, NULL, 0);
     594              :     else
     595            0 :         data->free_count = 0;
     596              : 
     597            7 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_PV_COUNT");
     598            7 :     if (value)
     599            7 :         data->pv_count = g_ascii_strtoull (value, NULL, 0);
     600              :     else
     601            0 :         data->pv_count = 0;
     602              : 
     603            7 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_EXPORTED");
     604            7 :     if (value && g_strcmp0 (value, "exported") == 0)
     605            0 :         data->exported = TRUE;
     606              :     else
     607            7 :         data->exported = FALSE;
     608              : 
     609            7 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VG_TAGS");
     610            7 :     if (value)
     611            7 :         data->vg_tags = g_strsplit (value, ",", -1);
     612              :     else
     613            0 :         data->vg_tags = NULL;
     614              : 
     615            7 :     if (free_table)
     616            7 :         g_hash_table_destroy (table);
     617              : 
     618            7 :     return data;
     619              : }
     620              : 
     621            8 : static gchar **prepare_sublvs (gchar **values, gchar *extra_value) {
     622              :   /* LVM2 guarantees: No "/dev/" prefixes or "[unknown]" in a list of sub-lvs. */
     623            8 :   gboolean found_extra = FALSE;
     624           24 :   for (int i = 0; values[i]; i++) {
     625           16 :     gchar *paren = strrchr (values[i], '(');
     626           16 :     if (paren) {
     627              :       /* LVM2 guarantees: start offsets of sub-lvs are always zero. */
     628           16 :       *paren = '\0';
     629              :     }
     630           16 :     if (g_strcmp0 (extra_value, values[i]) == 0)
     631            0 :       found_extra = TRUE;
     632              :   }
     633            8 :   if (extra_value && *extra_value && !found_extra) {
     634            0 :     int len = g_strv_length (values);
     635            0 :     gchar **new_values = g_new0 (gchar *, len+2);
     636            0 :     for (int j = 0; j < len; j++)
     637            0 :       new_values[j] = values[j];
     638            0 :     new_values[len] = g_strdup (extra_value);
     639            0 :     g_free (values);
     640            0 :     values = new_values;
     641              :   }
     642            8 :   return values;
     643              : }
     644              : 
     645           88 : static BDLVMLVdata* get_lv_data_from_table (GHashTable *table, gboolean free_table) {
     646           88 :     BDLVMLVdata *data = g_new0 (BDLVMLVdata, 1);
     647           88 :     gchar *value = NULL;
     648              : 
     649           88 :     data->lv_name = g_strdup (g_hash_table_lookup (table, "LVM2_LV_NAME"));
     650           88 :     data->vg_name = g_strdup (g_hash_table_lookup (table, "LVM2_VG_NAME"));
     651           88 :     data->uuid = g_strdup (g_hash_table_lookup (table, "LVM2_LV_UUID"));
     652              : 
     653           88 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_LV_SIZE");
     654           88 :     if (value)
     655           88 :         data->size = g_ascii_strtoull (value, NULL, 0);
     656              :     else
     657            0 :         data->size = 0;
     658              : 
     659           88 :     data->attr = g_strdup (g_hash_table_lookup (table, "LVM2_LV_ATTR"));
     660              : 
     661           88 :     value = g_hash_table_lookup (table, "LVM2_SEGTYPE");
     662           88 :     if (g_strcmp0 (value, "error") == 0) {
     663              :       /* A segment type "error" appears when "vgreduce
     664              :        * --removemissing" replaces a missing PV with a device mapper
     665              :        * "error" target.  It very likely was a "linear" segment before that
     666              :        * and will again be "linear" after repair.  Let's not expose
     667              :        * this implementation detail.
     668              :        */
     669            2 :       value = "linear";
     670              :     }
     671           88 :     data->segtype = g_strdup (value);
     672              : 
     673           88 :     data->origin = g_strdup (g_hash_table_lookup (table, "LVM2_ORIGIN"));
     674           88 :     data->pool_lv = g_strdup (g_hash_table_lookup (table, "LVM2_POOL_LV"));
     675           88 :     data->data_lv = g_strdup (g_hash_table_lookup (table, "LVM2_DATA_LV"));
     676           88 :     data->metadata_lv = g_strdup (g_hash_table_lookup (table, "LVM2_METADATA_LV"));
     677           88 :     data->roles = g_strdup (g_hash_table_lookup (table, "LVM2_LV_ROLE"));
     678              : 
     679           88 :     data->move_pv = g_strdup (g_hash_table_lookup (table, "LVM2_MOVE_PV"));
     680              : 
     681           88 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_DATA_PERCENT");
     682           88 :     if (value)
     683           88 :         data->data_percent = g_ascii_strtoull (value, NULL, 0);
     684              :     else
     685            0 :         data->data_percent = 0;
     686              : 
     687           88 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_METADATA_PERCENT");
     688           88 :     if (value)
     689           88 :         data->metadata_percent = g_ascii_strtoull (value, NULL, 0);
     690              :     else
     691            0 :         data->metadata_percent = 0;
     692              : 
     693           88 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_COPY_PERCENT");
     694           88 :     if (value)
     695           88 :         data->copy_percent = g_ascii_strtoull (value, NULL, 0);
     696              :     else
     697            0 :         data->copy_percent = 0;
     698              : 
     699           88 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_LV_TAGS");
     700           88 :     if (value)
     701           88 :         data->lv_tags = g_strsplit (value, ",", -1);
     702              :     else
     703            0 :         data->lv_tags = NULL;
     704              : 
     705              :     /* replace '[' and ']' (marking LVs as internal) with spaces and then
     706              :        remove all the leading and trailing whitespace */
     707           88 :     g_strstrip (g_strdelimit (data->pool_lv, "[]", ' '));
     708           88 :     g_strstrip (g_strdelimit (data->data_lv, "[]", ' '));
     709           88 :     g_strstrip (g_strdelimit (data->metadata_lv, "[]", ' '));
     710              : 
     711           88 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_DEVICES");
     712           88 :     if (value) {
     713           25 :       gchar **values = g_strsplit (value, ",", -1);
     714              : 
     715              :       /* If values starts with "/dev/", we have a single PV.
     716              : 
     717              :          If the list is empty, this is probably an "error" segment
     718              :          resulting from a "vgreduce --removemissing" operation.
     719              : 
     720              :          If the value starts with "[unknown]", it is a segment with a
     721              :          missing PV that hasn't been converted to an "error" segment
     722              :          yet.
     723              : 
     724              :          Otherwise it is a list of sub-lvs.
     725              : 
     726              :          LVM2 guarantees: only one entry if the first is a PV
     727              :          Additional segments are added in merge_lv_data below.
     728              :       */
     729           25 :       if (!values[0] || g_str_has_prefix (values[0], "[unknown]")) {
     730            4 :         data->segs = g_new0 (BDLVMSEGdata *, 1);
     731            4 :         data->segs[0] = NULL;
     732            4 :         g_strfreev (values);
     733           21 :       } else if (g_str_has_prefix (values[0], "/dev/")) {
     734           17 :         data->segs = g_new0 (BDLVMSEGdata *, 2);
     735           17 :         data->segs[0] = g_new0 (BDLVMSEGdata, 1);
     736           17 :         data->segs[1] = NULL;
     737              : 
     738           17 :         gchar *paren = strrchr (values[0], '(');
     739           17 :         if (paren) {
     740           17 :           data->segs[0]->pv_start_pe = atoi (paren+1);
     741           17 :           *paren = '\0';
     742              :         }
     743           17 :         data->segs[0]->pvdev = g_strdup (values[0]);
     744           17 :         value = (gchar*) g_hash_table_lookup (table, "LVM2_SEG_SIZE_PE");
     745           17 :         if (value)
     746           17 :           data->segs[0]->size_pe = g_ascii_strtoull (value, NULL, 0);
     747           17 :         g_strfreev (values);
     748              :       } else {
     749            4 :         data->data_lvs = prepare_sublvs (values, data->data_lv);
     750            4 :         value = (gchar*) g_hash_table_lookup (table, "LVM2_METADATA_DEVICES");
     751            4 :         data->metadata_lvs = prepare_sublvs (g_strsplit (value ?: "", ",", -1), data->metadata_lv);
     752              :       }
     753              :     }
     754              : 
     755           88 :     if (free_table)
     756           88 :         g_hash_table_destroy (table);
     757              : 
     758           88 :     return data;
     759              : }
     760              : 
     761            1 : static void merge_lv_data (BDLVMLVdata *data, BDLVMLVdata *more_data) {
     762              :   /* LVM2 guarantees:
     763              :      - more_data->data_lvs is NULL
     764              :      - more_data->metadata_lvs is NULL
     765              :      - more_data->segs has zero or one entry
     766              :      - more_data->seg_type is the same as data->seg_type (after mapping "error" to "linear")
     767              :   */
     768              : 
     769            1 :   if (more_data->segs && more_data->segs[0]) {
     770              :     int i;
     771            2 :     for (i = 0; data->segs && data->segs[i]; i++)
     772              :       ;
     773              : 
     774            1 :     BDLVMSEGdata **new_segs = g_new0 (BDLVMSEGdata *, i+2);
     775            2 :     for (i = 0; data->segs && data->segs[i]; i++)
     776            1 :       new_segs[i] = data->segs[i];
     777            1 :     new_segs[i] = more_data->segs[0];
     778            1 :     g_free (data->segs);
     779            1 :     data->segs = new_segs;
     780            1 :     more_data->segs[0] = NULL;
     781              :   }
     782            1 : }
     783              : 
     784           10 : static BDLVMVDOPooldata* get_vdo_data_from_table (GHashTable *table, gboolean free_table) {
     785           10 :     BDLVMVDOPooldata *data = g_new0 (BDLVMVDOPooldata, 1);
     786           10 :     gchar *value = NULL;
     787              : 
     788           10 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VDO_OPERATING_MODE");
     789           10 :     if (g_strcmp0 (value, "recovering") == 0)
     790            0 :         data->operating_mode = BD_LVM_VDO_MODE_RECOVERING;
     791           10 :     else if (g_strcmp0 (value, "read-only") == 0)
     792            0 :         data->operating_mode = BD_LVM_VDO_MODE_READ_ONLY;
     793           10 :     else if (g_strcmp0 (value, "normal") == 0)
     794           10 :         data->operating_mode = BD_LVM_VDO_MODE_NORMAL;
     795              :     else {
     796            0 :         bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Unknown VDO operating mode: %s", value);
     797            0 :         data->operating_mode = BD_LVM_VDO_MODE_UNKNOWN;
     798              :     }
     799              : 
     800           10 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VDO_COMPRESSION_STATE");
     801           10 :     if (g_strcmp0 (value, "online") == 0)
     802            8 :         data->compression_state = BD_LVM_VDO_COMPRESSION_ONLINE;
     803            2 :     else if (g_strcmp0 (value, "offline") == 0)
     804            2 :         data->compression_state = BD_LVM_VDO_COMPRESSION_OFFLINE;
     805              :     else {
     806            0 :         bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Unknown VDO compression state: %s", value);
     807            0 :         data->compression_state = BD_LVM_VDO_COMPRESSION_UNKNOWN;
     808              :     }
     809              : 
     810           10 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VDO_INDEX_STATE");
     811           10 :     if (g_strcmp0 (value, "error") == 0)
     812            0 :         data->index_state = BD_LVM_VDO_INDEX_ERROR;
     813           10 :     else if (g_strcmp0 (value, "closed") == 0)
     814            0 :         data->index_state = BD_LVM_VDO_INDEX_CLOSED;
     815           10 :     else if (g_strcmp0 (value, "opening") == 0)
     816            5 :         data->index_state = BD_LVM_VDO_INDEX_OPENING;
     817            5 :     else if (g_strcmp0 (value, "closing") == 0)
     818            1 :         data->index_state = BD_LVM_VDO_INDEX_CLOSING;
     819            4 :     else if (g_strcmp0 (value, "offline") == 0)
     820            0 :         data->index_state = BD_LVM_VDO_INDEX_OFFLINE;
     821            4 :     else if (g_strcmp0 (value, "online") == 0)
     822            4 :         data->index_state = BD_LVM_VDO_INDEX_ONLINE;
     823              :     else {
     824            0 :         bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Unknown VDO index state: %s", value);
     825            0 :         data->index_state = BD_LVM_VDO_INDEX_UNKNOWN;
     826              :     }
     827              : 
     828           10 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VDO_WRITE_POLICY");
     829           10 :     if (g_strcmp0 (value, "auto") == 0)
     830            9 :         data->write_policy = BD_LVM_VDO_WRITE_POLICY_AUTO;
     831            1 :     else if (g_strcmp0 (value, "sync") == 0)
     832            1 :         data->write_policy = BD_LVM_VDO_WRITE_POLICY_SYNC;
     833            0 :     else if (g_strcmp0 (value, "async") == 0)
     834            0 :         data->write_policy = BD_LVM_VDO_WRITE_POLICY_ASYNC;
     835              :     else {
     836            0 :         bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Unknown VDO write policy: %s", value);
     837            0 :         data->write_policy = BD_LVM_VDO_WRITE_POLICY_UNKNOWN;
     838              :     }
     839              : 
     840           10 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VDO_INDEX_MEMORY_SIZE");
     841           10 :     if (value)
     842           10 :         data->index_memory_size = g_ascii_strtoull (value, NULL, 0);
     843              :     else
     844            0 :         data->index_memory_size = 0;
     845              : 
     846           10 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VDO_USED_SIZE");
     847           10 :     if (value)
     848           10 :         data->used_size = g_ascii_strtoull (value, NULL, 0);
     849              :     else
     850            0 :         data->used_size = 0;
     851              : 
     852           10 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VDO_SAVING_PERCENT");
     853           10 :     if (value)
     854           10 :         data->saving_percent = g_ascii_strtoull (value, NULL, 0);
     855              :     else
     856            0 :         data->saving_percent = 0;
     857              : 
     858           10 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VDO_COMPRESSION");
     859           10 :     if (value && g_strcmp0 (value, "enabled") == 0)
     860            8 :         data->compression = TRUE;
     861              :     else
     862            2 :         data->compression = FALSE;
     863              : 
     864           10 :     value = (gchar*) g_hash_table_lookup (table, "LVM2_VDO_DEDUPLICATION");
     865           10 :     if (value && g_strcmp0 (value, "enabled") == 0)
     866            9 :         data->deduplication = TRUE;
     867              :     else
     868            1 :         data->deduplication = FALSE;
     869              : 
     870           10 :     if (free_table)
     871           10 :         g_hash_table_destroy (table);
     872              : 
     873           10 :     return data;
     874              : }
     875              : 
     876              : /**
     877              :  * bd_lvm_pvcreate:
     878              :  * @device: the device to make PV from
     879              :  * @data_alignment: data (first PE) alignment or 0 to use the default
     880              :  * @metadata_size: size of the area reserved for metadata or 0 to use the default
     881              :  * @extra: (nullable) (array zero-terminated=1): extra options for the PV creation
     882              :  *                                                 (just passed to LVM as is)
     883              :  * @error: (out) (optional): place to store error (if any)
     884              :  *
     885              :  * Returns: whether the PV was successfully created or not
     886              :  *
     887              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_CREATE
     888              :  */
     889           83 : gboolean bd_lvm_pvcreate (const gchar *device, guint64 data_alignment, guint64 metadata_size, const BDExtraArg **extra, GError **error) {
     890           83 :     const gchar *args[5] = {"pvcreate", device, NULL, NULL, NULL};
     891           83 :     guint next_arg = 2;
     892           83 :     gchar *dataalign_str = NULL;
     893           83 :     gchar *metadata_str = NULL;
     894           83 :     gboolean ret = FALSE;
     895              : 
     896           83 :     if (data_alignment != 0) {
     897            1 :         dataalign_str = g_strdup_printf ("--dataalignment=%"G_GUINT64_FORMAT"K", data_alignment / 1024);
     898            1 :         args[next_arg++] = dataalign_str;
     899              :     }
     900              : 
     901           83 :     if (metadata_size != 0) {
     902            1 :         metadata_str = g_strdup_printf ("--metadatasize=%"G_GUINT64_FORMAT"K", metadata_size / 1024);
     903            1 :         args[next_arg++] = metadata_str;
     904              :     }
     905              : 
     906           83 :     ret = call_lvm_and_report_error (args, extra, TRUE, error);
     907           83 :     g_free (dataalign_str);
     908           83 :     g_free (metadata_str);
     909              : 
     910           83 :     return ret;
     911              : }
     912              : 
     913              : /**
     914              :  * bd_lvm_pvresize:
     915              :  * @device: the device to resize
     916              :  * @size: the new requested size of the PV or 0 if it should be adjusted to device's size
     917              :  * @extra: (nullable) (array zero-terminated=1): extra options for the PV resize
     918              :  *                                                 (just passed to LVM as is)
     919              :  * @error: (out) (optional): place to store error (if any)
     920              :  *
     921              :  * Returns: whether the PV's size was successfully changed or not
     922              :  *
     923              :  * If given @size different from 0, sets the PV's size to the given value (see
     924              :  * pvresize(8)). If given @size 0, adjusts the PV's size to the underlying
     925              :  * block device's size.
     926              :  *
     927              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
     928              :  */
     929            4 : gboolean bd_lvm_pvresize (const gchar *device, guint64 size, const BDExtraArg **extra, GError **error) {
     930            4 :     gchar *size_str = NULL;
     931            4 :     const gchar *args[6] = {"pvresize", "-y", NULL, NULL, NULL, NULL};
     932            4 :     guint8 next_pos = 2;
     933            4 :     guint8 to_free_pos = 0;
     934            4 :     gboolean ret = FALSE;
     935              : 
     936            4 :     if (size != 0) {
     937            4 :         size_str = g_strdup_printf ("%"G_GUINT64_FORMAT"K", size / 1024);
     938            4 :         args[next_pos] = "--setphysicalvolumesize";
     939            4 :         next_pos++;
     940            4 :         args[next_pos] = size_str;
     941            4 :         to_free_pos = next_pos;
     942            4 :         next_pos++;
     943              :     }
     944              : 
     945            4 :     args[next_pos] = device;
     946              : 
     947            4 :     ret = call_lvm_and_report_error (args, extra, TRUE, error);
     948            4 :     if (to_free_pos > 0)
     949            4 :         g_free ((gchar *) args[to_free_pos]);
     950              : 
     951            4 :     return ret;
     952              : }
     953              : 
     954              : /**
     955              :  * bd_lvm_pvremove:
     956              :  * @device: the PV device to be removed/destroyed
     957              :  * @extra: (nullable) (array zero-terminated=1): extra options for the PV removal
     958              :  *                                                 (just passed to LVM as is)
     959              :  * @error: (out) (optional): place to store error (if any)
     960              :  *
     961              :  * Returns: whether the PV was successfully removed/destroyed or not
     962              :  *
     963              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_REMOVE
     964              :  */
     965          154 : gboolean bd_lvm_pvremove (const gchar *device, const BDExtraArg **extra, GError **error) {
     966              :     /* one has to be really persuasive to remove a PV (the double --force is not
     967              :        bug, at least not in this code) */
     968          154 :     const gchar *args[6] = {"pvremove", "--force", "--force", "--yes", device, NULL};
     969              : 
     970          154 :     return call_lvm_and_report_error (args, extra, TRUE, error);
     971              : }
     972              : 
     973            1 : static gboolean extract_pvmove_progress (const gchar *line, guint8 *completion) {
     974            1 :     gchar *num_start = NULL;
     975            1 :     gint n_scanned = 0;
     976            1 :     guint8 try_completion = 0;
     977              : 
     978            1 :     num_start = strrchr (line, ' ');
     979            1 :     if (!num_start)
     980            0 :         return FALSE;
     981            1 :     num_start++;
     982            1 :     n_scanned = sscanf (num_start, "%hhu", &try_completion);
     983            1 :     if (n_scanned == 1) {
     984            1 :         *completion = try_completion;
     985            1 :         return TRUE;
     986              :     }
     987            0 :     return FALSE;
     988              : }
     989              : 
     990              : /**
     991              :  * bd_lvm_pvmove:
     992              :  * @src: the PV device to move extents off of
     993              :  * @dest: (nullable): the PV device to move extents onto or %NULL
     994              :  * @extra: (nullable) (array zero-terminated=1): extra options for the PV move
     995              :  *                                                 (just passed to LVM as is)
     996              :  * @error: (out) (optional): place to store error (if any)
     997              :  *
     998              :  * Returns: whether the extents from the @src PV where successfully moved or not
     999              :  *
    1000              :  * If @dest is %NULL, VG allocation rules are used for the extents from the @src
    1001              :  * PV (see pvmove(8)).
    1002              :  *
    1003              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1004              :  */
    1005            1 : gboolean bd_lvm_pvmove (const gchar *src, const gchar *dest, const BDExtraArg **extra, GError **error) {
    1006            1 :     const gchar *args[6] = {"pvmove", "-i", "1", src, NULL, NULL};
    1007            1 :     gint status = 0;
    1008            1 :     if (dest)
    1009            1 :         args[4] = dest;
    1010              : 
    1011            1 :     return bd_utils_exec_and_report_progress (args, extra, extract_pvmove_progress, &status, error);
    1012              : }
    1013              : 
    1014              : /**
    1015              :  * bd_lvm_pvscan:
    1016              :  * @device: (nullable): the device to scan for PVs or %NULL
    1017              :  * @update_cache: whether to update the lvmetad cache or not
    1018              :  * @extra: (nullable) (array zero-terminated=1): extra options for the PV scan
    1019              :  *                                                 (just passed to LVM as is)
    1020              :  * @error: (out) (optional): place to store error (if any)
    1021              :  *
    1022              :  * Returns: whether the system or @device was successfully scanned for PVs or not
    1023              :  *
    1024              :  * The @device argument is used only if @update_cache is %TRUE. Otherwise the
    1025              :  * whole system is scanned for PVs.
    1026              :  *
    1027              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1028              :  */
    1029            5 : gboolean bd_lvm_pvscan (const gchar *device, gboolean update_cache, const BDExtraArg **extra, GError **error) {
    1030            5 :     const gchar *args[4] = {"pvscan", NULL, NULL, NULL};
    1031            5 :     if (update_cache) {
    1032            3 :         args[1] = "--cache";
    1033            3 :         args[2] = device;
    1034              :     }
    1035              :     else
    1036            2 :         if (device)
    1037            0 :             bd_utils_log_format (BD_UTILS_LOG_WARNING, "Ignoring the device argument in pvscan (cache update not requested)");
    1038              : 
    1039            5 :     return call_lvm_and_report_error (args, extra, TRUE, error);
    1040              : }
    1041              : 
    1042           11 : static gboolean _manage_lvm_tags (const gchar *devspec, const gchar **tags, const gchar *action, const gchar *cmd, GError **error) {
    1043           11 :     guint tags_len = g_strv_length ((gchar **) tags);
    1044           11 :     const gchar **argv = g_new0 (const gchar*, 2 * tags_len + 3);
    1045           11 :     guint next_arg = 0;
    1046           11 :     gboolean success = FALSE;
    1047              : 
    1048           11 :     argv[next_arg++] = cmd;
    1049           31 :     for (guint i = 0; i < tags_len; i++) {
    1050           20 :         argv[next_arg++] = action;
    1051           20 :         argv[next_arg++] = tags[i];
    1052              :     }
    1053           11 :     argv[next_arg++] = devspec;
    1054           11 :     argv[next_arg] = NULL;
    1055              : 
    1056           11 :     success = call_lvm_and_report_error (argv, NULL, TRUE, error);
    1057           11 :     g_free (argv);
    1058           11 :     return success;
    1059              : }
    1060              : 
    1061              : /**
    1062              :  * bd_lvm_add_pv_tags:
    1063              :  * @device: the device to set PV tags for
    1064              :  * @tags: (array zero-terminated=1): list of tags to add
    1065              :  * @error: (out) (optional): place to store error (if any)
    1066              :  *
    1067              :  * Returns: whether the tags were successfully added to @device or not
    1068              :  *
    1069              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1070              :  */
    1071            3 : gboolean bd_lvm_add_pv_tags (const gchar *device, const gchar **tags, GError **error) {
    1072            3 :     return _manage_lvm_tags (device, tags, "--addtag", "pvchange", error);
    1073              : }
    1074              : 
    1075              : /**
    1076              :  * bd_lvm_delete_pv_tags:
    1077              :  * @device: the device to set PV tags for
    1078              :  * @tags: (array zero-terminated=1): list of tags to remove
    1079              :  * @error: (out) (optional): place to store error (if any)
    1080              :  *
    1081              :  * Returns: whether the tags were successfully removed from @device or not
    1082              :  *
    1083              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1084              :  */
    1085            2 : gboolean bd_lvm_delete_pv_tags (const gchar *device, const gchar **tags, GError **error) {
    1086            2 :     return _manage_lvm_tags (device, tags, "--deltag", "pvchange", error);
    1087              : }
    1088              : 
    1089              : /**
    1090              :  * bd_lvm_pvinfo:
    1091              :  * @device: a PV to get information about or %NULL
    1092              :  * @error: (out) (optional): place to store error (if any)
    1093              :  *
    1094              :  * Returns: (transfer full): information about the PV on the given @device or
    1095              :  * %NULL in case of error (the @error) gets populated in those cases)
    1096              :  *
    1097              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1098              :  */
    1099            9 : BDLVMPVdata* bd_lvm_pvinfo (const gchar *device, GError **error) {
    1100            9 :     const gchar *args[10] = {"pvs", "--unit=b", "--nosuffix", "--nameprefixes",
    1101              :                        "--unquoted", "--noheadings",
    1102              :                        "-o", "pv_name,pv_uuid,pv_free,pv_size,pe_start,vg_name,vg_uuid,vg_size," \
    1103              :                        "vg_free,vg_extent_size,vg_extent_count,vg_free_count,pv_count,pv_tags,pv_missing",
    1104              :                        device, NULL};
    1105            9 :     GHashTable *table = NULL;
    1106            9 :     gboolean success = FALSE;
    1107            9 :     gchar *output = NULL;
    1108            9 :     gchar **lines = NULL;
    1109            9 :     gchar **lines_p = NULL;
    1110              :     guint num_items;
    1111              : 
    1112            9 :     success = call_lvm_and_capture_output (args, NULL, &output, error);
    1113            9 :     if (!success)
    1114              :         /* the error is already populated from the call */
    1115            0 :         return NULL;
    1116              : 
    1117            9 :     lines = g_strsplit (output, "\n", 0);
    1118            9 :     g_free (output);
    1119              : 
    1120            9 :     for (lines_p = lines; *lines_p; lines_p++) {
    1121            9 :         table = parse_lvm_vars ((*lines_p), &num_items);
    1122            9 :         if (table && (num_items == 15)) {
    1123            9 :             g_clear_error (error);
    1124            9 :             g_strfreev (lines);
    1125            9 :             return get_pv_data_from_table (table, TRUE);
    1126              :         } else
    1127            0 :             if (table)
    1128            0 :                 g_hash_table_destroy (table);
    1129              :     }
    1130            0 :     g_strfreev (lines);
    1131              : 
    1132              :     /* getting here means no usable info was found */
    1133            0 :     g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
    1134              :                  "Failed to parse information about the PV");
    1135            0 :     return NULL;
    1136              : }
    1137              : 
    1138              : /**
    1139              :  * bd_lvm_pvs:
    1140              :  * @error: (out) (optional): place to store error (if any)
    1141              :  *
    1142              :  * Returns: (array zero-terminated=1): information about PVs found in the system
    1143              :  *
    1144              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1145              :  */
    1146            4 : BDLVMPVdata** bd_lvm_pvs (GError **error) {
    1147            4 :     const gchar *args[9] = {"pvs", "--unit=b", "--nosuffix", "--nameprefixes",
    1148              :                        "--unquoted", "--noheadings",
    1149              :                        "-o", "pv_name,pv_uuid,pv_free,pv_size,pe_start,vg_name,vg_uuid,vg_size," \
    1150              :                        "vg_free,vg_extent_size,vg_extent_count,vg_free_count,pv_count,pv_tags,pv_missing",
    1151              :                        NULL};
    1152            4 :     GHashTable *table = NULL;
    1153            4 :     gboolean success = FALSE;
    1154            4 :     gchar *output = NULL;
    1155            4 :     gchar **lines = NULL;
    1156            4 :     gchar **lines_p = NULL;
    1157              :     guint num_items;
    1158              :     GPtrArray *pvs;
    1159            4 :     BDLVMPVdata *pvdata = NULL;
    1160              : 
    1161            4 :     pvs = g_ptr_array_new ();
    1162              : 
    1163            4 :     success = call_lvm_and_capture_output (args, NULL, &output, error);
    1164            4 :     if (!success) {
    1165            1 :         if (g_error_matches (*error, BD_UTILS_EXEC_ERROR, BD_UTILS_EXEC_ERROR_NOOUT)) {
    1166              :             /* no output => no VGs, not an error */
    1167            1 :             g_clear_error (error);
    1168              :             /* return an empty list */
    1169            1 :             g_ptr_array_add (pvs, NULL);
    1170            1 :             return (BDLVMPVdata **) g_ptr_array_free (pvs, FALSE);
    1171              :         }
    1172              :         else {
    1173              :             /* the error is already populated from the call */
    1174            0 :             g_ptr_array_free (pvs, TRUE);
    1175            0 :             return NULL;
    1176              :         }
    1177              :     }
    1178              : 
    1179            3 :     lines = g_strsplit (output, "\n", 0);
    1180            3 :     g_free (output);
    1181              : 
    1182           12 :     for (lines_p = lines; *lines_p; lines_p++) {
    1183            9 :         table = parse_lvm_vars ((*lines_p), &num_items);
    1184            9 :         if (table && (num_items == 15)) {
    1185              :             /* valid line, try to parse and record it */
    1186            6 :             pvdata = get_pv_data_from_table (table, TRUE);
    1187            6 :             if (pvdata)
    1188            6 :                 g_ptr_array_add (pvs, pvdata);
    1189              :         } else
    1190            3 :             if (table)
    1191            3 :                 g_hash_table_destroy (table);
    1192              :     }
    1193              : 
    1194            3 :     g_strfreev (lines);
    1195              : 
    1196            3 :     if (pvs->len == 0) {
    1197            0 :         g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
    1198              :                      "Failed to parse information about PVs");
    1199            0 :         g_ptr_array_free (pvs, TRUE);
    1200            0 :         return NULL;
    1201              :     }
    1202              : 
    1203              :     /* returning NULL-terminated array of BDLVMPVdata */
    1204            3 :     g_ptr_array_add (pvs, NULL);
    1205            3 :     return (BDLVMPVdata **) g_ptr_array_free (pvs, FALSE);
    1206              : }
    1207              : 
    1208              : /**
    1209              :  * bd_lvm_vgcreate:
    1210              :  * @name: name of the newly created VG
    1211              :  * @pv_list: (array zero-terminated=1): list of PVs the newly created VG should use
    1212              :  * @pe_size: PE size or 0 if the default value should be used
    1213              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VG creation
    1214              :  *                                                 (just passed to LVM as is)
    1215              :  * @error: (out) (optional): place to store error (if any)
    1216              :  *
    1217              :  * Returns: whether the VG @name was successfully created or not
    1218              :  *
    1219              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_CREATE
    1220              :  */
    1221           47 : gboolean bd_lvm_vgcreate (const gchar *name, const gchar **pv_list, guint64 pe_size, const BDExtraArg **extra, GError **error) {
    1222           47 :     guint i = 0;
    1223           47 :     guint pv_list_len = pv_list ? g_strv_length ((gchar **) pv_list) : 0;
    1224           47 :     const gchar **argv = g_new0 (const gchar*, pv_list_len + 5);
    1225           47 :     pe_size = RESOLVE_PE_SIZE (pe_size);
    1226           47 :     gboolean success = FALSE;
    1227              : 
    1228           47 :     argv[0] = "vgcreate";
    1229           47 :     argv[1] = "-s";
    1230           47 :     argv[2] = g_strdup_printf ("%"G_GUINT64_FORMAT"K", pe_size / 1024);
    1231           47 :     argv[3] = name;
    1232          124 :     for (i=4; i < (pv_list_len + 4); i++) {
    1233           77 :         argv[i] = pv_list[i-4];
    1234              :     }
    1235           47 :     argv[i] = NULL;
    1236              : 
    1237           47 :     success = call_lvm_and_report_error (argv, extra, TRUE, error);
    1238           47 :     g_free ((gchar *) argv[2]);
    1239           47 :     g_free (argv);
    1240              : 
    1241           47 :     return success;
    1242              : }
    1243              : 
    1244              : /**
    1245              :  * bd_lvm_vgremove:
    1246              :  * @vg_name: name of the to be removed VG
    1247              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VG removal
    1248              :  *                                                 (just passed to LVM as is)
    1249              :  * @error: (out) (optional): place to store error (if any)
    1250              :  *
    1251              :  * Returns: whether the VG was successfully removed or not
    1252              :  *
    1253              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_REMOVE
    1254              :  */
    1255           50 : gboolean bd_lvm_vgremove (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
    1256           50 :     const gchar *args[4] = {"vgremove", "--force", vg_name, NULL};
    1257              : 
    1258           50 :     return call_lvm_and_report_error (args, extra, TRUE, error);
    1259              : }
    1260              : 
    1261              : /**
    1262              :  * bd_lvm_vgrename:
    1263              :  * @old_vg_name: old name of the VG to rename
    1264              :  * @new_vg_name: new name for the @old_vg_name VG
    1265              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VG rename
    1266              :  *                                                 (just passed to LVM as is)
    1267              :  * @error: (out) (optional): place to store error (if any)
    1268              :  *
    1269              :  * Returns: whether the VG was successfully renamed or not
    1270              :  *
    1271              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1272              :  */
    1273            3 : gboolean bd_lvm_vgrename (const gchar *old_vg_name, const gchar *new_vg_name, const BDExtraArg **extra, GError **error) {
    1274            3 :     const gchar *args[4] = {"vgrename", old_vg_name, new_vg_name, NULL};
    1275              : 
    1276            3 :     return call_lvm_and_report_error (args, extra, TRUE, error);
    1277              : }
    1278              : 
    1279              : /**
    1280              :  * bd_lvm_vgactivate:
    1281              :  * @vg_name: name of the to be activated VG
    1282              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VG activation
    1283              :  *                                                 (just passed to LVM as is)
    1284              :  * @error: (out) (optional): place to store error (if any)
    1285              :  *
    1286              :  * Returns: whether the VG was successfully activated or not
    1287              :  *
    1288              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1289              :  */
    1290            3 : gboolean bd_lvm_vgactivate (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
    1291            3 :     const gchar *args[4] = {"vgchange", "-ay", vg_name, NULL};
    1292              : 
    1293            3 :     return call_lvm_and_report_error (args, extra, TRUE, error);
    1294              : }
    1295              : 
    1296              : /**
    1297              :  * bd_lvm_vgdeactivate:
    1298              :  * @vg_name: name of the to be deactivated VG
    1299              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VG deactivation
    1300              :  *                                                 (just passed to LVM as is)
    1301              :  * @error: (out) (optional): place to store error (if any)
    1302              :  *
    1303              :  * Returns: whether the VG was successfully deactivated or not
    1304              :  *
    1305              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1306              :  */
    1307            3 : gboolean bd_lvm_vgdeactivate (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
    1308            3 :     const gchar *args[4] = {"vgchange", "-an", vg_name, NULL};
    1309              : 
    1310            3 :     return call_lvm_and_report_error (args, extra, TRUE, error);
    1311              : }
    1312              : 
    1313              : /**
    1314              :  * bd_lvm_vgextend:
    1315              :  * @vg_name: name of the to be extended VG
    1316              :  * @device: PV device to extend the @vg_name VG with
    1317              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VG extension
    1318              :  *                                                 (just passed to LVM as is)
    1319              :  * @error: (out) (optional): place to store error (if any)
    1320              :  *
    1321              :  * Returns: whether the VG @vg_name was successfully extended with the given @device or not.
    1322              :  *
    1323              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1324              :  */
    1325            4 : gboolean bd_lvm_vgextend (const gchar *vg_name, const gchar *device, const BDExtraArg **extra, GError **error) {
    1326            4 :     const gchar *args[4] = {"vgextend", vg_name, device, NULL};
    1327              : 
    1328            4 :     return call_lvm_and_report_error (args, extra, TRUE, error);
    1329              : }
    1330              : 
    1331              : /**
    1332              :  * bd_lvm_vgreduce:
    1333              :  * @vg_name: name of the to be reduced VG
    1334              :  * @device: (nullable): PV device the @vg_name VG should be reduced of or %NULL
    1335              :  *                        if the VG should be reduced of the missing PVs
    1336              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VG reduction
    1337              :  *                                                 (just passed to LVM as is)
    1338              :  * @error: (out) (optional): place to store error (if any)
    1339              :  *
    1340              :  * Returns: whether the VG @vg_name was successfully reduced of the given @device or not
    1341              :  *
    1342              :  * Note: This function does not move extents off of the PV before removing
    1343              :  *       it from the VG. You must do that first by calling #bd_lvm_pvmove.
    1344              :  *
    1345              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1346              :  */
    1347            4 : gboolean bd_lvm_vgreduce (const gchar *vg_name, const gchar *device, const BDExtraArg **extra, GError **error) {
    1348            4 :     const gchar *args[5] = {"vgreduce", NULL, NULL, NULL, NULL};
    1349              : 
    1350            4 :     if (!device) {
    1351            2 :         args[1] = "--removemissing";
    1352            2 :         args[2] = "--force";
    1353            2 :         args[3] = vg_name;
    1354              :     } else {
    1355            2 :         args[1] = vg_name;
    1356            2 :         args[2] = device;
    1357              :     }
    1358              : 
    1359            4 :     return call_lvm_and_report_error (args, extra, TRUE, error);
    1360              : }
    1361              : 
    1362              : /**
    1363              :  * bd_lvm_add_vg_tags:
    1364              :  * @vg_name: the VG to set tags on
    1365              :  * @tags: (array zero-terminated=1): list of tags to add
    1366              :  * @error: (out) (optional): place to store error (if any)
    1367              :  *
    1368              :  * Returns: whether the tags were successfully added to @vg_name or not
    1369              :  *
    1370              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1371              :  */
    1372            2 : gboolean bd_lvm_add_vg_tags (const gchar *vg_name, const gchar **tags, GError **error) {
    1373            2 :     return _manage_lvm_tags (vg_name, tags, "--addtag", "vgchange", error);
    1374              : }
    1375              : 
    1376              : /**
    1377              :  * bd_lvm_delete_vg_tags:
    1378              :  * @vg_name: the VG to set tags on
    1379              :  * @tags: (array zero-terminated=1): list of tags to remove
    1380              :  * @error: (out) (optional): place to store error (if any)
    1381              :  *
    1382              :  * Returns: whether the tags were successfully removed from @vg_name or not
    1383              :  *
    1384              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1385              :  */
    1386            1 : gboolean bd_lvm_delete_vg_tags (const gchar *vg_name, const gchar **tags, GError **error) {
    1387            1 :     return _manage_lvm_tags (vg_name, tags, "--deltag", "vgchange", error);
    1388              : }
    1389              : 
    1390            0 : static gboolean _vglock_start_stop (const gchar *vg_name, gboolean start, const BDExtraArg **extra, GError **error) {
    1391            0 :     const gchar *args[4] = {"vgchange", NULL, vg_name, NULL};
    1392              : 
    1393            0 :     if (start)
    1394            0 :         args[1] = "--lockstart";
    1395              :     else
    1396            0 :         args[1] = "--lockstop";
    1397              : 
    1398            0 :     return call_lvm_and_report_error (args, extra, TRUE, error);
    1399              : }
    1400              : 
    1401              : /**
    1402              :  * bd_lvm_vglock_start:
    1403              :  * @vg_name: a shared VG to start the lockspace in lvmlockd
    1404              :  * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command
    1405              :  *                                               (just passed to LVM as is)
    1406              :  * @error: (out) (optional): place to store error (if any)
    1407              :  *
    1408              :  * Returns: whether the lock was successfully started for @vg_name or not
    1409              :  *
    1410              :  * Tech category: %BD_LVM_TECH_SHARED-%BD_LVM_TECH_MODE_MODIFY
    1411              :  */
    1412            0 : gboolean bd_lvm_vglock_start (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
    1413            0 :     return _vglock_start_stop (vg_name, TRUE, extra, error);
    1414              : }
    1415              : 
    1416              : /**
    1417              :  * bd_lvm_vglock_stop:
    1418              :  * @vg_name: a shared VG to stop the lockspace in lvmlockd
    1419              :  * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command
    1420              :  *                                               (just passed to LVM as is)
    1421              :  * @error: (out) (optional): place to store error (if any)
    1422              :  *
    1423              :  * Returns: whether the lock was successfully stopped for @vg_name or not
    1424              :  *
    1425              :  * Tech category: %BD_LVM_TECH_SHARED-%BD_LVM_TECH_MODE_MODIFY
    1426              :  */
    1427            0 : gboolean bd_lvm_vglock_stop (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
    1428            0 :     return _vglock_start_stop (vg_name, FALSE, extra, error);
    1429              : }
    1430              : 
    1431              : /**
    1432              :  * bd_lvm_vginfo:
    1433              :  * @vg_name: a VG to get information about
    1434              :  * @error: (out) (optional): place to store error (if any)
    1435              :  *
    1436              :  * Returns: (transfer full): information about the @vg_name VG or %NULL in case
    1437              :  * of error (the @error) gets populated in those cases)
    1438              :  *
    1439              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1440              :  */
    1441            6 : BDLVMVGdata* bd_lvm_vginfo (const gchar *vg_name, GError **error) {
    1442            6 :     const gchar *args[10] = {"vgs", "--noheadings", "--nosuffix", "--nameprefixes",
    1443              :                        "--unquoted", "--units=b",
    1444              :                        "-o", "name,uuid,size,free,extent_size,extent_count,free_count,pv_count,vg_exported,vg_tags",
    1445              :                        vg_name, NULL};
    1446              : 
    1447            6 :     GHashTable *table = NULL;
    1448            6 :     gboolean success = FALSE;
    1449            6 :     gchar *output = NULL;
    1450            6 :     gchar **lines = NULL;
    1451            6 :     gchar **lines_p = NULL;
    1452              :     guint num_items;
    1453              : 
    1454            6 :     success = call_lvm_and_capture_output (args, NULL, &output, error);
    1455            6 :     if (!success)
    1456              :         /* the error is already populated from the call */
    1457            0 :         return NULL;
    1458              : 
    1459            6 :     lines = g_strsplit (output, "\n", 0);
    1460            6 :     g_free (output);
    1461              : 
    1462            6 :     for (lines_p = lines; *lines_p; lines_p++) {
    1463            6 :         table = parse_lvm_vars ((*lines_p), &num_items);
    1464            6 :         if (table && (num_items == 10)) {
    1465            6 :             g_strfreev (lines);
    1466            6 :             return get_vg_data_from_table (table, TRUE);
    1467              :         } else
    1468            0 :             if (table)
    1469            0 :                 g_hash_table_destroy (table);
    1470              :     }
    1471            0 :     g_strfreev (lines);
    1472              : 
    1473              :     /* getting here means no usable info was found */
    1474            0 :     g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
    1475              :                  "Failed to parse information about the VG");
    1476            0 :     return NULL;
    1477              : }
    1478              : 
    1479              : /**
    1480              :  * bd_lvm_vgs:
    1481              :  * @error: (out) (optional): place to store error (if any)
    1482              :  *
    1483              :  * Returns: (array zero-terminated=1): information about VGs found in the system
    1484              :  *
    1485              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1486              :  */
    1487            2 : BDLVMVGdata** bd_lvm_vgs (GError **error) {
    1488            2 :     const gchar *args[9] = {"vgs", "--noheadings", "--nosuffix", "--nameprefixes",
    1489              :                       "--unquoted", "--units=b",
    1490              :                       "-o", "name,uuid,size,free,extent_size,extent_count,free_count,pv_count,vg_tags",
    1491              :                       NULL};
    1492            2 :     GHashTable *table = NULL;
    1493            2 :     gboolean success = FALSE;
    1494            2 :     gchar *output = NULL;
    1495            2 :     gchar **lines = NULL;
    1496            2 :     gchar **lines_p = NULL;
    1497              :     guint num_items;
    1498              :     GPtrArray *vgs;
    1499            2 :     BDLVMVGdata *vgdata = NULL;
    1500            2 :     GError *l_error = NULL;
    1501              : 
    1502            2 :     vgs = g_ptr_array_new ();
    1503              : 
    1504            2 :     success = call_lvm_and_capture_output (args, NULL, &output, &l_error);
    1505            2 :     if (!success) {
    1506            1 :         if (g_error_matches (l_error, BD_UTILS_EXEC_ERROR, BD_UTILS_EXEC_ERROR_NOOUT)) {
    1507              :             /* no output => no VGs, not an error */
    1508            1 :             g_clear_error (&l_error);
    1509              :             /* return an empty list */
    1510            1 :             g_ptr_array_add (vgs, NULL);
    1511            1 :             return (BDLVMVGdata **) g_ptr_array_free (vgs, FALSE);
    1512              :         } else {
    1513              :             /* the error is already populated from the call */
    1514            0 :             g_ptr_array_free (vgs, TRUE);
    1515            0 :             g_propagate_error (error, l_error);
    1516            0 :             return NULL;
    1517              :        }
    1518              :     }
    1519              : 
    1520            1 :     lines = g_strsplit (output, "\n", 0);
    1521            1 :     g_free (output);
    1522              : 
    1523            3 :     for (lines_p = lines; *lines_p; lines_p++) {
    1524            2 :         table = parse_lvm_vars ((*lines_p), &num_items);
    1525            2 :         if (table && (num_items == 9)) {
    1526              :             /* valid line, try to parse and record it */
    1527            1 :             vgdata = get_vg_data_from_table (table, TRUE);
    1528            1 :             if (vgdata)
    1529            1 :                 g_ptr_array_add (vgs, vgdata);
    1530              :         } else
    1531            1 :             if (table)
    1532            1 :                 g_hash_table_destroy (table);
    1533              :     }
    1534              : 
    1535            1 :     g_strfreev (lines);
    1536              : 
    1537            1 :     if (vgs->len == 0) {
    1538            0 :         g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
    1539              :                      "Failed to parse information about VGs");
    1540            0 :         g_ptr_array_free (vgs, TRUE);
    1541            0 :         return NULL;
    1542              :     }
    1543              : 
    1544              :     /* returning NULL-terminated array of BDLVMVGdata */
    1545            1 :     g_ptr_array_add (vgs, NULL);
    1546            1 :     return (BDLVMVGdata **) g_ptr_array_free (vgs, FALSE);
    1547              : }
    1548              : 
    1549              : /**
    1550              :  * bd_lvm_lvorigin:
    1551              :  * @vg_name: name of the VG containing the queried LV
    1552              :  * @lv_name: name of the queried LV
    1553              :  * @error: (out) (optional): place to store error (if any)
    1554              :  *
    1555              :  * Returns: (transfer full): the origin volume for the @vg_name/@lv_name LV or
    1556              :  * %NULL if failed to determine (@error) is set in those cases)
    1557              :  *
    1558              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1559              :  */
    1560            1 : gchar* bd_lvm_lvorigin (const gchar *vg_name, const gchar *lv_name, GError **error) {
    1561            1 :     gboolean success = FALSE;
    1562            1 :     gchar *output = NULL;
    1563            1 :     const gchar *args[6] = {"lvs", "--noheadings", "-o", "origin", NULL, NULL};
    1564            1 :     args[4] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1565              : 
    1566            1 :     success = call_lvm_and_capture_output (args, NULL, &output, error);
    1567            1 :     g_free ((gchar *) args[4]);
    1568              : 
    1569            1 :     if (!success)
    1570              :         /* the error is already populated from the call */
    1571            0 :         return NULL;
    1572              : 
    1573            1 :     return g_strstrip (output);
    1574              : }
    1575              : 
    1576              : /**
    1577              :  * bd_lvm_lvcreate:
    1578              :  * @vg_name: name of the VG to create a new LV in
    1579              :  * @lv_name: name of the to-be-created LV
    1580              :  * @size: requested size of the new LV
    1581              :  * @type: (nullable): type of the new LV ("striped", "raid1",..., see lvcreate (8))
    1582              :  * @pv_list: (nullable) (array zero-terminated=1): list of PVs the newly created LV should use or %NULL
    1583              :  * if not specified
    1584              :  * @extra: (nullable) (array zero-terminated=1): extra options for the LV creation
    1585              :  *                                                 (just passed to LVM as is)
    1586              :  * @error: (out) (optional): place to store error (if any)
    1587              :  *
    1588              :  * Returns: whether the given @vg_name/@lv_name LV was successfully created or not
    1589              :  *
    1590              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_CREATE
    1591              :  */
    1592           48 : gboolean bd_lvm_lvcreate (const gchar *vg_name, const gchar *lv_name, guint64 size, const gchar *type, const gchar **pv_list, const BDExtraArg **extra, GError **error) {
    1593           48 :     guint8 pv_list_len = pv_list ? g_strv_length ((gchar **) pv_list) : 0;
    1594           48 :     const gchar **args = g_new0 (const gchar*, pv_list_len + 10);
    1595           48 :     gboolean success = FALSE;
    1596           48 :     guint64 i = 0;
    1597           48 :     guint64 j = 0;
    1598           48 :     gchar *size_str = NULL;
    1599           48 :     gchar *type_str = NULL;
    1600              : 
    1601           48 :     args[i++] = "lvcreate";
    1602           48 :     args[i++] = "-n";
    1603           48 :     args[i++] = lv_name;
    1604           48 :     args[i++] = "-L";
    1605           48 :     size_str = g_strdup_printf ("%"G_GUINT64_FORMAT"K", size/1024);
    1606           48 :     args[i++] = size_str;
    1607           48 :     args[i++] = "-y";
    1608           48 :     if (type) {
    1609            3 :         if (g_strcmp0 (type, "striped") == 0) {
    1610            1 :             args[i++] = "--stripes";
    1611            1 :             type_str = g_strdup_printf ("%d", pv_list_len);
    1612            1 :             args[i++] = type_str;
    1613              :         } else {
    1614            2 :             args[i++] = "--type";
    1615            2 :             args[i++] = type;
    1616              :         }
    1617              :     }
    1618           48 :     args[i++] = vg_name;
    1619              : 
    1620           96 :     for (j=0; j < pv_list_len; j++)
    1621           48 :         args[i++] = pv_list[j];
    1622              : 
    1623           48 :     args[i] = NULL;
    1624              : 
    1625           48 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    1626           48 :     g_free (size_str);
    1627           48 :     g_free (type_str);
    1628           48 :     g_free (args);
    1629              : 
    1630           48 :     return success;
    1631              : }
    1632              : 
    1633              : /**
    1634              :  * bd_lvm_lvremove:
    1635              :  * @vg_name: name of the VG containing the to-be-removed LV
    1636              :  * @lv_name: name of the to-be-removed LV
    1637              :  * @force: whether to force removal or not
    1638              :  * @extra: (nullable) (array zero-terminated=1): extra options for the LV removal
    1639              :  *                                                 (just passed to LVM as is)
    1640              :  * @error: (out) (optional): place to store error (if any)
    1641              :  *
    1642              :  * Returns: whether the @vg_name/@lv_name LV was successfully removed or not
    1643              :  *
    1644              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_REMOVE
    1645              :  */
    1646           55 : gboolean bd_lvm_lvremove (const gchar *vg_name, const gchar *lv_name, gboolean force, const BDExtraArg **extra, GError **error) {
    1647              :     /* '--yes' is needed if DISCARD is enabled */
    1648           55 :     const gchar *args[5] = {"lvremove", "--yes", NULL, NULL, NULL};
    1649           55 :     guint8 next_arg = 2;
    1650           55 :     gboolean success = FALSE;
    1651              : 
    1652           55 :     if (force) {
    1653           53 :         args[next_arg] = "--force";
    1654           53 :         next_arg++;
    1655              :     }
    1656              : 
    1657           55 :     args[next_arg] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1658              : 
    1659           55 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    1660           55 :     g_free ((gchar *) args[next_arg]);
    1661              : 
    1662           55 :     return success;
    1663              : }
    1664              : 
    1665              : /**
    1666              :  * bd_lvm_lvrename:
    1667              :  * @vg_name: name of the VG containing the to-be-renamed LV
    1668              :  * @lv_name: name of the to-be-renamed LV
    1669              :  * @new_name: new name for the @vg_name/@lv_name LV
    1670              :  * @extra: (nullable) (array zero-terminated=1): extra options for the LV rename
    1671              :  *                                                 (just passed to LVM as is)
    1672              :  * @error: (out) (optional): place to store error (if any)
    1673              :  *
    1674              :  * Returns: whether the @vg_name/@lv_name LV was successfully renamed to
    1675              :  * @vg_name/@new_name or not
    1676              :  *
    1677              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1678              :  */
    1679            7 : gboolean bd_lvm_lvrename (const gchar *vg_name, const gchar *lv_name, const gchar *new_name, const BDExtraArg **extra, GError **error) {
    1680            7 :     const gchar *args[5] = {"lvrename", vg_name, lv_name, new_name, NULL};
    1681            7 :     return call_lvm_and_report_error (args, extra, TRUE, error);
    1682              : }
    1683              : 
    1684              : 
    1685              : /**
    1686              :  * bd_lvm_lvresize:
    1687              :  * @vg_name: name of the VG containing the to-be-resized LV
    1688              :  * @lv_name: name of the to-be-resized LV
    1689              :  * @size: the requested new size of the LV
    1690              :  * @extra: (nullable) (array zero-terminated=1): extra options for the LV resize
    1691              :  *                                                 (just passed to LVM as is)
    1692              :  * @error: (out) (optional): place to store error (if any)
    1693              :  *
    1694              :  * Returns: whether the @vg_name/@lv_name LV was successfully resized or not
    1695              :  *
    1696              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1697              :  */
    1698           10 : gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 size, const BDExtraArg **extra, GError **error) {
    1699           10 :     const gchar *args[8] = {"lvresize", "--force", "-L", NULL, NULL, NULL, NULL, NULL};
    1700           10 :     gboolean success = FALSE;
    1701           10 :     guint8 next_arg = 4;
    1702           20 :     g_autofree gchar *lvspec = NULL;
    1703              : 
    1704           10 :     args[3] = g_strdup_printf ("%"G_GUINT64_FORMAT"K", size/1024);
    1705              : 
    1706              :     /* Starting with 2.03.19 we need to add an extra option to avoid
    1707              :        any filesystem related checks by lvresize.
    1708              :     */
    1709           10 :     success = bd_utils_check_util_version (deps[DEPS_LVM].name, LVM_VERSION_FSRESIZE,
    1710           10 :                                            deps[DEPS_LVM].ver_arg, deps[DEPS_LVM].ver_regexp, NULL);
    1711           10 :     if (success) {
    1712           10 :       args[next_arg++] = "--fs";
    1713           10 :       args[next_arg++] = "ignore";
    1714              :     }
    1715              : 
    1716           10 :     lvspec = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1717           10 :     args[next_arg++] = lvspec;
    1718              : 
    1719           10 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    1720           10 :     g_free ((gchar *) args[3]);
    1721              : 
    1722           10 :     return success;
    1723              : }
    1724              : 
    1725              : /**
    1726              :  * bd_lvm_lvrepair:
    1727              :  * @vg_name: name of the VG containing the to-be-repaired LV
    1728              :  * @lv_name: name of the to-be-repaired LV
    1729              :  * @pv_list: (array zero-terminated=1): list of PVs to be used for the repair
    1730              :  * @extra: (nullable) (array zero-terminated=1): extra options for the LV repair
    1731              :  *                                                 (just passed to LVM as is)
    1732              :  * @error: (out) (optional): place to store error (if any)
    1733              :  *
    1734              :  * Returns: whether the @vg_name/@lv_name LV was successfully repaired or not
    1735              :  *
    1736              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1737              :  */
    1738            1 : gboolean bd_lvm_lvrepair (const gchar *vg_name, const gchar *lv_name, const gchar **pv_list, const BDExtraArg **extra, GError **error) {
    1739            1 :     guint i = 0;
    1740            1 :     guint pv_list_len = pv_list ? g_strv_length ((gchar **) pv_list) : 0;
    1741            1 :     const gchar **argv = g_new0 (const gchar*, pv_list_len + 5);
    1742            1 :     gboolean success = FALSE;
    1743              : 
    1744            1 :     argv[0] = "lvconvert";
    1745            1 :     argv[1] = "--repair";
    1746            1 :     argv[2] = "--yes";
    1747            1 :     argv[3] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1748            2 :     for (i=4; i < (pv_list_len + 4); i++) {
    1749            1 :         argv[i] = pv_list[i-4];
    1750              :     }
    1751            1 :     argv[i] = NULL;
    1752              : 
    1753            1 :     success = call_lvm_and_report_error (argv, extra, TRUE, error);
    1754            1 :     g_free ((gchar *) argv[3]);
    1755            1 :     g_free (argv);
    1756              : 
    1757            1 :     return success;
    1758              : }
    1759              : 
    1760              : /**
    1761              :  * bd_lvm_lvactivate:
    1762              :  * @vg_name: name of the VG containing the to-be-activated LV
    1763              :  * @lv_name: name of the to-be-activated LV
    1764              :  * @ignore_skip: whether to ignore the skip flag or not
    1765              :  * @shared: whether to activate the LV in shared mode (used for shared LVM setups with lvmlockd,
    1766              :  *          use %FALSE if not sure)
    1767              :  * @extra: (nullable) (array zero-terminated=1): extra options for the LV activation
    1768              :  *                                                 (just passed to LVM as is)
    1769              :  * @error: (out) (optional): place to store error (if any)
    1770              :  *
    1771              :  * Returns: whether the @vg_name/@lv_name LV was successfully activated or not
    1772              :  *
    1773              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1774              :  */
    1775            6 : gboolean bd_lvm_lvactivate (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, gboolean shared, const BDExtraArg **extra, GError **error) {
    1776            6 :     const gchar *args[5] = {"lvchange", NULL, NULL, NULL, NULL};
    1777            6 :     guint8 next_arg = 2;
    1778            6 :     gboolean success = FALSE;
    1779              : 
    1780            6 :     if (shared)
    1781            1 :         args[1] = "-asy";
    1782              :     else
    1783            5 :         args[1] = "-ay";
    1784              : 
    1785            6 :     if (ignore_skip) {
    1786            6 :         args[next_arg] = "-K";
    1787            6 :         next_arg++;
    1788              :     }
    1789            6 :     args[next_arg] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1790              : 
    1791            6 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    1792            6 :     g_free ((gchar *) args[next_arg]);
    1793              : 
    1794            6 :     return success;
    1795              : }
    1796              : 
    1797              : /**
    1798              :  * bd_lvm_lvdeactivate:
    1799              :  * @vg_name: name of the VG containing the to-be-deactivated LV
    1800              :  * @lv_name: name of the to-be-deactivated LV
    1801              :  * @extra: (nullable) (array zero-terminated=1): extra options for the LV deactivation
    1802              :  *                                                 (just passed to LVM as is)
    1803              :  * @error: (out) (optional): place to store error (if any)
    1804              :  *
    1805              :  * Returns: whether the @vg_name/@lv_name LV was successfully deactivated or not
    1806              :  *
    1807              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
    1808              :  */
    1809           13 : gboolean bd_lvm_lvdeactivate (const gchar *vg_name, const gchar *lv_name, const BDExtraArg **extra, GError **error) {
    1810           13 :     const gchar *args[4] = {"lvchange", "-an", NULL, NULL};
    1811           13 :     gboolean success = FALSE;
    1812              : 
    1813           13 :     args[2] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1814              : 
    1815           13 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    1816           13 :     g_free ((gchar *) args[2]);
    1817              : 
    1818           13 :     return success;
    1819              : }
    1820              : 
    1821              : /**
    1822              :  * bd_lvm_lvsnapshotcreate:
    1823              :  * @vg_name: name of the VG containing the LV a new snapshot should be created of
    1824              :  * @origin_name: name of the LV a new snapshot should be created of
    1825              :  * @snapshot_name: name of the to-be-created snapshot
    1826              :  * @size: requested size for the snapshot
    1827              :  * @extra: (nullable) (array zero-terminated=1): extra options for the LV snapshot creation
    1828              :  *                                                 (just passed to LVM as is)
    1829              :  * @error: (out) (optional): place to store error (if any)
    1830              :  *
    1831              :  * Returns: whether the @snapshot_name snapshot of the @vg_name/@origin_name LV
    1832              :  * was successfully created or not.
    1833              :  *
    1834              :  * Tech category: %BD_LVM_TECH_BASIC_SNAP-%BD_LVM_TECH_MODE_CREATE
    1835              :  */
    1836            1 : gboolean bd_lvm_lvsnapshotcreate (const gchar *vg_name, const gchar *origin_name, const gchar *snapshot_name, guint64 size, const BDExtraArg **extra, GError **error) {
    1837            1 :     const gchar *args[8] = {"lvcreate", "-s", "-L", NULL, "-n", snapshot_name, NULL, NULL};
    1838            1 :     gboolean success = FALSE;
    1839              : 
    1840            1 :     args[3] = g_strdup_printf ("%"G_GUINT64_FORMAT"K", size / 1024);
    1841            1 :     args[6] = g_strdup_printf ("%s/%s", vg_name, origin_name);
    1842              : 
    1843            1 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    1844            1 :     g_free ((gchar *) args[3]);
    1845            1 :     g_free ((gchar *) args[6]);
    1846              : 
    1847            1 :     return success;
    1848              : }
    1849              : 
    1850              : /**
    1851              :  * bd_lvm_lvsnapshotmerge:
    1852              :  * @vg_name: name of the VG containing the to-be-merged LV snapshot
    1853              :  * @snapshot_name: name of the to-be-merged LV snapshot
    1854              :  * @extra: (nullable) (array zero-terminated=1): extra options for the LV snapshot merge
    1855              :  *                                                 (just passed to LVM as is)
    1856              :  * @error: (out) (optional): place to store error (if any)
    1857              :  *
    1858              :  * Returns: whether the @vg_name/@snapshot_name LV snapshot was successfully merged or not
    1859              :  *
    1860              :  * Tech category: %BD_LVM_TECH_BASIC_SNAP-%BD_LVM_TECH_MODE_MODIFY
    1861              :  */
    1862            1 : gboolean bd_lvm_lvsnapshotmerge (const gchar *vg_name, const gchar *snapshot_name, const BDExtraArg **extra, GError **error) {
    1863            1 :     const gchar *args[4] = {"lvconvert", "--merge", NULL, NULL};
    1864            1 :     gboolean success = FALSE;
    1865              : 
    1866            1 :     args[2] = g_strdup_printf ("%s/%s", vg_name, snapshot_name);
    1867              : 
    1868            1 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    1869            1 :     g_free ((gchar *) args[2]);
    1870              : 
    1871            1 :     return success;
    1872              : }
    1873              : 
    1874              : /**
    1875              :  * bd_lvm_add_lv_tags:
    1876              :  * @vg_name: name of the VG that contains the LV to set tags on
    1877              :  * @lv_name: name of the LV to set tags on
    1878              :  * @tags: (array zero-terminated=1): list of tags to add
    1879              :  * @error: (out) (optional): place to store error (if any)
    1880              :  *
    1881              :  * Returns: whether the tags were successfully added to @device or not
    1882              :  *
    1883              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1884              :  */
    1885            2 : gboolean bd_lvm_add_lv_tags (const gchar *vg_name, const gchar *lv_name, const gchar **tags, GError **error) {
    1886            4 :     g_autofree gchar *lvspec = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1887            2 :     return _manage_lvm_tags (lvspec, tags, "--addtag", "lvchange", error);
    1888              : }
    1889              : 
    1890              : /**
    1891              :  * bd_lvm_delete_lv_tags:
    1892              :  * @vg_name: name of the VG that contains the LV to set tags on
    1893              :  * @lv_name: name of the LV to set tags on
    1894              :  * @tags: (array zero-terminated=1): list of tags to remove
    1895              :  * @error: (out) (optional): place to store error (if any)
    1896              :  *
    1897              :  * Returns: whether the tags were successfully removed from @device or not
    1898              :  *
    1899              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1900              :  */
    1901            1 : gboolean bd_lvm_delete_lv_tags (const gchar *vg_name, const gchar *lv_name, const gchar **tags, GError **error) {
    1902            2 :     g_autofree gchar *lvspec = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1903            1 :     return _manage_lvm_tags (lvspec, tags, "--deltag", "lvchange", error);
    1904              : }
    1905              : 
    1906              : /**
    1907              :  * bd_lvm_lvinfo:
    1908              :  * @vg_name: name of the VG that contains the LV to get information about
    1909              :  * @lv_name: name of the LV to get information about
    1910              :  * @error: (out) (optional): place to store error (if any)
    1911              :  *
    1912              :  * Returns: (transfer full): information about the @vg_name/@lv_name LV or %NULL in case
    1913              :  * of error (the @error) gets populated in those cases)
    1914              :  *
    1915              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    1916              :  */
    1917           39 : BDLVMLVdata* bd_lvm_lvinfo (const gchar *vg_name, const gchar *lv_name, GError **error) {
    1918           39 :     const gchar *args[11] = {"lvs", "--noheadings", "--nosuffix", "--nameprefixes",
    1919              :                        "--unquoted", "--units=b", "-a",
    1920              :                        "-o", "vg_name,lv_name,lv_uuid,lv_size,lv_attr,segtype,origin,pool_lv,data_lv,metadata_lv,role,move_pv,data_percent,metadata_percent,copy_percent,lv_tags",
    1921              :                        NULL, NULL};
    1922              : 
    1923           39 :     GHashTable *table = NULL;
    1924           39 :     gboolean success = FALSE;
    1925           39 :     gchar *output = NULL;
    1926           39 :     gchar **lines = NULL;
    1927           39 :     gchar **lines_p = NULL;
    1928              :     guint num_items;
    1929              : 
    1930           39 :     args[9] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1931              : 
    1932           39 :     success = call_lvm_and_capture_output (args, NULL, &output, error);
    1933           39 :     g_free ((gchar *) args[9]);
    1934              : 
    1935           39 :     if (!success)
    1936              :         /* the error is already populated from the call */
    1937            0 :         return NULL;
    1938              : 
    1939           39 :     lines = g_strsplit (output, "\n", 0);
    1940           39 :     g_free (output);
    1941              : 
    1942           39 :     for (lines_p = lines; *lines_p; lines_p++) {
    1943           39 :         table = parse_lvm_vars ((*lines_p), &num_items);
    1944           39 :         if (table && (num_items == 16)) {
    1945           39 :             g_strfreev (lines);
    1946           39 :             return get_lv_data_from_table (table, TRUE);
    1947              :         } else
    1948            0 :             if (table)
    1949            0 :                 g_hash_table_destroy (table);
    1950              :     }
    1951            0 :     g_strfreev (lines);
    1952              : 
    1953              :     /* getting here means no usable info was found */
    1954            0 :     g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
    1955              :                  "Failed to parse information about the LV");
    1956            0 :     return NULL;
    1957              : }
    1958              : 
    1959            4 : BDLVMLVdata* bd_lvm_lvinfo_tree (const gchar *vg_name, const gchar *lv_name, GError **error) {
    1960            4 :     const gchar *args[11] = {"lvs", "--noheadings", "--nosuffix", "--nameprefixes",
    1961              :                        "--unquoted", "--units=b", "-a",
    1962              :                        "-o", "vg_name,lv_name,lv_uuid,lv_size,lv_attr,segtype,origin,pool_lv,data_lv,metadata_lv,role,move_pv,data_percent,metadata_percent,copy_percent,lv_tags,devices,metadata_devices,seg_size_pe",
    1963              :                        NULL, NULL};
    1964              : 
    1965            4 :     GHashTable *table = NULL;
    1966            4 :     gboolean success = FALSE;
    1967            4 :     gchar *output = NULL;
    1968            4 :     gchar **lines = NULL;
    1969            4 :     gchar **lines_p = NULL;
    1970              :     guint num_items;
    1971            4 :     BDLVMLVdata *result = NULL;
    1972              : 
    1973            4 :     args[9] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    1974              : 
    1975            4 :     success = call_lvm_and_capture_output (args, NULL, &output, error);
    1976            4 :     g_free ((gchar *) args[9]);
    1977              : 
    1978            4 :     if (!success)
    1979              :         /* the error is already populated from the call */
    1980            0 :         return NULL;
    1981              : 
    1982            4 :     lines = g_strsplit (output, "\n", 0);
    1983            4 :     g_free (output);
    1984              : 
    1985           13 :     for (lines_p = lines; *lines_p; lines_p++) {
    1986            9 :         table = parse_lvm_vars ((*lines_p), &num_items);
    1987           14 :         if (table && (num_items == 19)) {
    1988            5 :             BDLVMLVdata *lvdata = get_lv_data_from_table (table, TRUE);
    1989            5 :             if (result) {
    1990            1 :                 merge_lv_data (result, lvdata);
    1991            1 :                 bd_lvm_lvdata_free (lvdata);
    1992              :             } else
    1993            4 :                 result = lvdata;
    1994              :         } else {
    1995            4 :             if (table)
    1996            4 :                 g_hash_table_destroy (table);
    1997              :         }
    1998              :     }
    1999            4 :     g_strfreev (lines);
    2000              : 
    2001            4 :     if (result == NULL)
    2002            0 :       g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
    2003              :                    "Failed to parse information about the LV");
    2004            4 :     return result;
    2005              : }
    2006              : 
    2007              : /**
    2008              :  * bd_lvm_lvs:
    2009              :  * @vg_name: (nullable): name of the VG to get information about LVs from
    2010              :  * @error: (out) (optional): place to store error (if any)
    2011              :  *
    2012              :  * Returns: (array zero-terminated=1): information about LVs found in the given
    2013              :  * @vg_name VG or in system if @vg_name is %NULL
    2014              :  *
    2015              :  * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
    2016              :  */
    2017           14 : BDLVMLVdata** bd_lvm_lvs (const gchar *vg_name, GError **error) {
    2018           14 :     const gchar *args[11] = {"lvs", "--noheadings", "--nosuffix", "--nameprefixes",
    2019              :                        "--unquoted", "--units=b", "-a",
    2020              :                        "-o", "vg_name,lv_name,lv_uuid,lv_size,lv_attr,segtype,origin,pool_lv,data_lv,metadata_lv,role,move_pv,data_percent,metadata_percent,copy_percent,lv_tags",
    2021              :                        NULL, NULL};
    2022              : 
    2023           14 :     GHashTable *table = NULL;
    2024           14 :     gboolean success = FALSE;
    2025           14 :     gchar *output = NULL;
    2026           14 :     gchar **lines = NULL;
    2027           14 :     gchar **lines_p = NULL;
    2028              :     guint num_items;
    2029              :     GPtrArray *lvs;
    2030           14 :     BDLVMLVdata *lvdata = NULL;
    2031           14 :     GError *l_error = NULL;
    2032              : 
    2033           14 :     lvs = g_ptr_array_new ();
    2034              : 
    2035           14 :     if (vg_name)
    2036           12 :         args[9] = vg_name;
    2037              : 
    2038           14 :     success = call_lvm_and_capture_output (args, NULL, &output, &l_error);
    2039           14 :     if (!success) {
    2040            3 :         if (g_error_matches (l_error, BD_UTILS_EXEC_ERROR, BD_UTILS_EXEC_ERROR_NOOUT)) {
    2041              :             /* no output => no LVs, not an error */
    2042            3 :             g_clear_error (&l_error);
    2043              :             /* return an empty list */
    2044            3 :             g_ptr_array_add (lvs, NULL);
    2045            3 :             return (BDLVMLVdata **) g_ptr_array_free (lvs, FALSE);
    2046              :         }
    2047              :         else {
    2048              :             /* the error is already populated from the call */
    2049            0 :             g_ptr_array_free (lvs, TRUE);
    2050            0 :             g_propagate_error (error, l_error);
    2051            0 :             return NULL;
    2052              :         }
    2053              :     }
    2054              : 
    2055           11 :     lines = g_strsplit (output, "\n", 0);
    2056           11 :     g_free (output);
    2057              : 
    2058           46 :     for (lines_p = lines; *lines_p; lines_p++) {
    2059           35 :         table = parse_lvm_vars ((*lines_p), &num_items);
    2060           35 :         if (table && (num_items == 16)) {
    2061              :             /* valid line, try to parse and record it */
    2062           24 :             lvdata = get_lv_data_from_table (table, TRUE);
    2063           24 :             if (lvdata) {
    2064              :                 /* ignore duplicate entries in lvs output, these are caused by multi segments LVs */
    2065           46 :                 for (gsize i = 0; i < lvs->len; i++) {
    2066           23 :                     if (g_strcmp0 (((BDLVMLVdata *) g_ptr_array_index (lvs, i))->lv_name, lvdata->lv_name) == 0) {
    2067            1 :                         bd_utils_log_format (BD_UTILS_LOG_DEBUG,
    2068              :                                              "Duplicate LV entry for '%s' found in lvs output",
    2069              :                                              lvdata->lv_name);
    2070            1 :                         bd_lvm_lvdata_free (lvdata);
    2071            1 :                         lvdata = NULL;
    2072            1 :                         break;
    2073              :                     }
    2074              :                 }
    2075              : 
    2076           24 :                 if (lvdata)
    2077           23 :                     g_ptr_array_add (lvs, lvdata);
    2078              :             }
    2079              :         } else
    2080           11 :             if (table)
    2081           11 :                 g_hash_table_destroy (table);
    2082              :     }
    2083              : 
    2084           11 :     g_strfreev (lines);
    2085              : 
    2086           11 :     if (lvs->len == 0) {
    2087            0 :         g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
    2088              :                      "Failed to parse information about LVs");
    2089            0 :         g_ptr_array_free (lvs, TRUE);
    2090            0 :         return NULL;
    2091              :     }
    2092              : 
    2093              :     /* returning NULL-terminated array of BDLVMLVdata */
    2094           11 :     g_ptr_array_add (lvs, NULL);
    2095           11 :     return (BDLVMLVdata **) g_ptr_array_free (lvs, FALSE);
    2096              : }
    2097              : 
    2098            4 : BDLVMLVdata** bd_lvm_lvs_tree (const gchar *vg_name, GError **error) {
    2099            4 :     const gchar *args[11] = {"lvs", "--noheadings", "--nosuffix", "--nameprefixes",
    2100              :                        "--unquoted", "--units=b", "-a",
    2101              :                        "-o", "vg_name,lv_name,lv_uuid,lv_size,lv_attr,segtype,origin,pool_lv,data_lv,metadata_lv,role,move_pv,data_percent,metadata_percent,copy_percent,lv_tags,devices,metadata_devices,seg_size_pe",
    2102              :                        NULL, NULL};
    2103              : 
    2104            4 :     GHashTable *table = NULL;
    2105            4 :     gboolean success = FALSE;
    2106            4 :     gchar *output = NULL;
    2107            4 :     gchar **lines = NULL;
    2108            4 :     gchar **lines_p = NULL;
    2109              :     guint num_items;
    2110              :     GPtrArray *lvs;
    2111            4 :     BDLVMLVdata *lvdata = NULL;
    2112            4 :     GError *l_error = NULL;
    2113              : 
    2114            4 :     lvs = g_ptr_array_new ();
    2115              : 
    2116            4 :     if (vg_name)
    2117            4 :         args[9] = vg_name;
    2118              : 
    2119            4 :     success = call_lvm_and_capture_output (args, NULL, &output, &l_error);
    2120            4 :     if (!success) {
    2121            0 :         if (g_error_matches (l_error, BD_UTILS_EXEC_ERROR, BD_UTILS_EXEC_ERROR_NOOUT)) {
    2122              :             /* no output => no LVs, not an error */
    2123            0 :             g_clear_error (&l_error);
    2124              :             /* return an empty list */
    2125            0 :             g_ptr_array_add (lvs, NULL);
    2126            0 :             return (BDLVMLVdata **) g_ptr_array_free (lvs, FALSE);
    2127              :         }
    2128              :         else {
    2129              :             /* the error is already populated from the call */
    2130            0 :             g_ptr_array_free (lvs, TRUE);
    2131            0 :             g_propagate_error (error, l_error);
    2132            0 :             return NULL;
    2133              :         }
    2134              :     }
    2135              : 
    2136            4 :     lines = g_strsplit (output, "\n", 0);
    2137            4 :     g_free (output);
    2138              : 
    2139           28 :     for (lines_p = lines; *lines_p; lines_p++) {
    2140           24 :         table = parse_lvm_vars ((*lines_p), &num_items);
    2141           24 :         if (table && (num_items == 19)) {
    2142              :             /* valid line, try to parse and record it */
    2143           20 :             lvdata = get_lv_data_from_table (table, TRUE);
    2144           20 :             if (lvdata) {
    2145           60 :                 for (gsize i = 0; i < lvs->len; i++) {
    2146           40 :                     BDLVMLVdata *other = (BDLVMLVdata *) g_ptr_array_index (lvs, i);
    2147           40 :                     if (g_strcmp0 (other->lv_name, lvdata->lv_name) == 0) {
    2148            0 :                         merge_lv_data (other, lvdata);
    2149            0 :                         bd_lvm_lvdata_free (lvdata);
    2150            0 :                         lvdata = NULL;
    2151            0 :                         break;
    2152              :                     }
    2153              :                 }
    2154              : 
    2155           20 :                 if (lvdata)
    2156           20 :                     g_ptr_array_add (lvs, lvdata);
    2157              :             }
    2158              :         } else
    2159            4 :             if (table)
    2160            4 :                 g_hash_table_destroy (table);
    2161              :     }
    2162              : 
    2163            4 :     g_strfreev (lines);
    2164              : 
    2165            4 :     if (lvs->len == 0) {
    2166            0 :         g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
    2167              :                      "Failed to parse information about LVs");
    2168            0 :         g_ptr_array_free (lvs, TRUE);
    2169            0 :         return NULL;
    2170              :     }
    2171              : 
    2172              :     /* returning NULL-terminated array of BDLVMLVdata */
    2173            4 :     g_ptr_array_add (lvs, NULL);
    2174            4 :     return (BDLVMLVdata **) g_ptr_array_free (lvs, FALSE);
    2175              : }
    2176              : 
    2177              : /**
    2178              :  * bd_lvm_thpoolcreate:
    2179              :  * @vg_name: name of the VG to create a thin pool in
    2180              :  * @lv_name: name of the to-be-created pool LV
    2181              :  * @size: requested size of the to-be-created pool
    2182              :  * @md_size: requested metadata size or 0 to use the default
    2183              :  * @chunk_size: requested chunk size or 0 to use the default
    2184              :  * @profile: (nullable): profile to use (see lvm(8) for more information) or %NULL to use
    2185              :  *                         the default
    2186              :  * @extra: (nullable) (array zero-terminated=1): extra options for the thin pool creation
    2187              :  *                                                 (just passed to LVM as is)
    2188              :  * @error: (out) (optional): place to store error (if any)
    2189              :  *
    2190              :  * Returns: whether the @vg_name/@lv_name thin pool was successfully created or not
    2191              :  *
    2192              :  * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_CREATE
    2193              :  */
    2194            6 : gboolean bd_lvm_thpoolcreate (const gchar *vg_name, const gchar *lv_name, guint64 size, guint64 md_size, guint64 chunk_size, const gchar *profile, const BDExtraArg **extra, GError **error) {
    2195            6 :     const gchar *args[9] = {"lvcreate", "-T", "-L", NULL, NULL, NULL, NULL, NULL, NULL};
    2196            6 :     guint8 next_arg = 4;
    2197            6 :     gboolean success = FALSE;
    2198              : 
    2199            6 :     args[3] = g_strdup_printf ("%"G_GUINT64_FORMAT"K", size/1024);
    2200              : 
    2201            6 :     if (md_size != 0) {
    2202            6 :         args[next_arg] = g_strdup_printf ("--poolmetadatasize=%"G_GUINT64_FORMAT"K", md_size / 1024);
    2203            6 :         next_arg++;
    2204              :     }
    2205              : 
    2206            6 :     if (chunk_size != 0) {
    2207            6 :         args[next_arg] = g_strdup_printf ("--chunksize=%"G_GUINT64_FORMAT"K", chunk_size / 1024);
    2208            6 :         next_arg++;
    2209              :     }
    2210              : 
    2211            6 :     if (profile) {
    2212            4 :         args[next_arg] = g_strdup_printf ("--profile=%s", profile);
    2213            4 :         next_arg++;
    2214              :     }
    2215              : 
    2216            6 :     args[next_arg] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    2217              : 
    2218            6 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    2219            6 :     g_free ((gchar *) args[3]);
    2220            6 :     g_free ((gchar *) args[4]);
    2221            6 :     g_free ((gchar *) args[5]);
    2222            6 :     g_free ((gchar *) args[6]);
    2223            6 :     g_free ((gchar *) args[7]);
    2224              : 
    2225            6 :     return success;
    2226              : }
    2227              : 
    2228              : /**
    2229              :  * bd_lvm_thlvcreate:
    2230              :  * @vg_name: name of the VG containing the thin pool providing extents for the to-be-created thin LV
    2231              :  * @pool_name: name of the pool LV providing extents for the to-be-created thin LV
    2232              :  * @lv_name: name of the to-be-created thin LV
    2233              :  * @size: requested virtual size of the to-be-created thin LV
    2234              :  * @extra: (nullable) (array zero-terminated=1): extra options for the thin LV creation
    2235              :  *                                                 (just passed to LVM as is)
    2236              :  * @error: (out) (optional): place to store error (if any)
    2237              :  *
    2238              :  * Returns: whether the @vg_name/@lv_name thin LV was successfully created or not
    2239              :  *
    2240              :  * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_CREATE
    2241              :  */
    2242            2 : gboolean bd_lvm_thlvcreate (const gchar *vg_name, const gchar *pool_name, const gchar *lv_name, guint64 size, const BDExtraArg **extra, GError **error) {
    2243            2 :     const gchar *args[8] = {"lvcreate", "-T", NULL, "-V", NULL, "-n", lv_name, NULL};
    2244              :     gboolean success;
    2245              : 
    2246            2 :     args[2] = g_strdup_printf ("%s/%s", vg_name, pool_name);
    2247            2 :     args[4] = g_strdup_printf ("%"G_GUINT64_FORMAT"K", size / 1024);
    2248              : 
    2249            2 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    2250            2 :     g_free ((gchar *) args[2]);
    2251            2 :     g_free ((gchar *) args[4]);
    2252              : 
    2253            2 :     return success;
    2254              : }
    2255              : 
    2256              : /**
    2257              :  * bd_lvm_thlvpoolname:
    2258              :  * @vg_name: name of the VG containing the queried thin LV
    2259              :  * @lv_name: name of the queried thin LV
    2260              :  * @error: (out) (optional): place to store error (if any)
    2261              :  *
    2262              :  * Returns: (transfer full): the name of the pool volume for the @vg_name/@lv_name
    2263              :  * thin LV or %NULL if failed to determine (@error) is set in those cases)
    2264              :  *
    2265              :  * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_QUERY
    2266              :  */
    2267            2 : gchar* bd_lvm_thlvpoolname (const gchar *vg_name, const gchar *lv_name, GError **error) {
    2268            2 :     gboolean success = FALSE;
    2269            2 :     gchar *output = NULL;
    2270            2 :     const gchar *args[6] = {"lvs", "--noheadings", "-o", "pool_lv", NULL, NULL};
    2271            2 :     args[4] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    2272              : 
    2273            2 :     success = call_lvm_and_capture_output (args, NULL, &output, error);
    2274            2 :     g_free ((gchar *) args[4]);
    2275              : 
    2276            2 :     if (!success)
    2277              :         /* the error is already populated from the call */
    2278            0 :         return NULL;
    2279              : 
    2280            2 :     return g_strstrip (output);
    2281              : }
    2282              : 
    2283              : /**
    2284              :  * bd_lvm_thsnapshotcreate:
    2285              :  * @vg_name: name of the VG containing the thin LV a new snapshot should be created of
    2286              :  * @origin_name: name of the thin LV a new snapshot should be created of
    2287              :  * @snapshot_name: name of the to-be-created snapshot
    2288              :  * @pool_name: (nullable): name of the thin pool to create the snapshot in or %NULL if not specified
    2289              :  * @extra: (nullable) (array zero-terminated=1): extra options for the thin LV snapshot creation
    2290              :  *                                                 (just passed to LVM as is)
    2291              :  * @error: (out) (optional): place to store error (if any)
    2292              :  *
    2293              :  * Returns: whether the @snapshot_name snapshot of the @vg_name/@origin_name
    2294              :  * thin LV was successfully created or not.
    2295              :  *
    2296              :  * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_CREATE
    2297              :  */
    2298            1 : gboolean bd_lvm_thsnapshotcreate (const gchar *vg_name, const gchar *origin_name, const gchar *snapshot_name, const gchar *pool_name, const BDExtraArg **extra, GError **error) {
    2299            1 :     const gchar *args[8] = {"lvcreate", "-s", "-n", snapshot_name, NULL, NULL, NULL, NULL};
    2300            1 :     guint next_arg = 4;
    2301            1 :     gboolean success = FALSE;
    2302              : 
    2303            1 :     if (pool_name) {
    2304            1 :         args[next_arg] = "--thinpool";
    2305            1 :         next_arg++;
    2306            1 :         args[next_arg] = pool_name;
    2307            1 :         next_arg++;
    2308              :     }
    2309              : 
    2310            1 :     args[next_arg] = g_strdup_printf ("%s/%s", vg_name, origin_name);
    2311              : 
    2312            1 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    2313            1 :     g_free ((gchar *) args[next_arg]);
    2314              : 
    2315            1 :     return success;
    2316              : }
    2317              : 
    2318              : /**
    2319              :  * get_lv_type_from_flags: (skip)
    2320              :  * @meta: getting type for a (future) metadata LV
    2321              :  *
    2322              :  * Get LV type string from flags.
    2323              :  */
    2324           16 : static const gchar* get_lv_type_from_flags (BDLVMCachePoolFlags flags, gboolean meta, GError **error G_GNUC_UNUSED) {
    2325           16 :     if (!meta) {
    2326            8 :         if (flags & BD_LVM_CACHE_POOL_STRIPED)
    2327            1 :             return "striped";
    2328            7 :         else if (flags & BD_LVM_CACHE_POOL_RAID1)
    2329            0 :             return "raid1";
    2330            7 :         else if (flags & BD_LVM_CACHE_POOL_RAID5)
    2331            0 :             return "raid5";
    2332            7 :         else if (flags & BD_LVM_CACHE_POOL_RAID6)
    2333            0 :             return "raid6";
    2334            7 :         else if (flags & BD_LVM_CACHE_POOL_RAID10)
    2335            0 :             return "raid10";
    2336              :         else
    2337            7 :             return NULL;
    2338              :     } else {
    2339            8 :         if (flags & BD_LVM_CACHE_POOL_META_STRIPED)
    2340            0 :             return "striped";
    2341            8 :         else if (flags & BD_LVM_CACHE_POOL_META_RAID1)
    2342            1 :             return "raid1";
    2343            7 :         else if (flags & BD_LVM_CACHE_POOL_META_RAID5)
    2344            0 :             return "raid5";
    2345            7 :         else if (flags & BD_LVM_CACHE_POOL_META_RAID6)
    2346            0 :             return "raid6";
    2347            7 :         else if (flags & BD_LVM_CACHE_POOL_META_RAID10)
    2348            0 :             return "raid10";
    2349              :         else
    2350            7 :             return NULL;
    2351              :     }
    2352              : }
    2353              : 
    2354              : /**
    2355              :  * bd_lvm_cache_create_pool:
    2356              :  * @vg_name: name of the VG to create @pool_name in
    2357              :  * @pool_name: name of the cache pool LV to create
    2358              :  * @pool_size: desired size of the cache pool @pool_name
    2359              :  * @md_size: desired size of the @pool_name cache pool's metadata LV or 0 to
    2360              :  *           use the default
    2361              :  * @mode: cache mode of the @pool_name cache pool
    2362              :  * @flags: a combination of (ORed) #BDLVMCachePoolFlags
    2363              :  * @fast_pvs: (array zero-terminated=1): list of (fast) PVs to create the @pool_name
    2364              :  *                                       cache pool (and the metadata LV)
    2365              :  * @error: (out) (optional): place to store error (if any)
    2366              :  *
    2367              :  * Returns: whether the cache pool @vg_name/@pool_name was successfully created or not
    2368              :  *
    2369              :  * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_CREATE
    2370              :  */
    2371            8 : gboolean bd_lvm_cache_create_pool (const gchar *vg_name, const gchar *pool_name, guint64 pool_size, guint64 md_size, BDLVMCacheMode mode, BDLVMCachePoolFlags flags, const gchar **fast_pvs, GError **error) {
    2372            8 :     gboolean success = FALSE;
    2373            8 :     const gchar *type = NULL;
    2374            8 :     gchar *name = NULL;
    2375            8 :     gchar *msg = NULL;
    2376            8 :     guint64 progress_id = 0;
    2377            8 :     const gchar *args[10] = {"lvconvert", "-y", "--type", "cache-pool", "--poolmetadata", NULL, "--cachemode", NULL, NULL, NULL};
    2378            8 :     GError *l_error = NULL;
    2379              : 
    2380            8 :     msg = g_strdup_printf ("Started 'create cache pool %s/%s'", vg_name, pool_name);
    2381            8 :     progress_id = bd_utils_report_started (msg);
    2382            8 :     g_free (msg);
    2383              : 
    2384              :     /* create an LV for the pool */
    2385            8 :     type = get_lv_type_from_flags (flags, FALSE, NULL);
    2386            8 :     success = bd_lvm_lvcreate (vg_name, pool_name, pool_size, type, fast_pvs, NULL, &l_error);
    2387            8 :     if (!success) {
    2388            0 :         g_prefix_error (&l_error, "Failed to create the pool LV: ");
    2389            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2390            0 :         g_propagate_error (error, l_error);
    2391            0 :         return FALSE;
    2392              :     }
    2393              : 
    2394              :     /* 1/3 steps done */
    2395            8 :     bd_utils_report_progress (progress_id, 33, "Created the data LV");
    2396              : 
    2397              :     /* determine the size of the metadata LV */
    2398            8 :     type = get_lv_type_from_flags (flags, TRUE, NULL);
    2399            8 :     if (md_size == 0)
    2400            7 :         md_size = bd_lvm_cache_get_default_md_size (pool_size, &l_error);
    2401            8 :     if (l_error) {
    2402            0 :         g_prefix_error (&l_error, "Failed to determine size for the pool metadata LV: ");
    2403            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2404            0 :         g_propagate_error (error, l_error);
    2405            0 :         return FALSE;
    2406              :     }
    2407            8 :     name = g_strdup_printf ("%s_meta", pool_name);
    2408              : 
    2409              :     /* create the metadata LV */
    2410            8 :     success = bd_lvm_lvcreate (vg_name, name, md_size, type, fast_pvs, NULL, &l_error);
    2411            8 :     if (!success) {
    2412            0 :         g_free (name);
    2413            0 :         g_prefix_error (&l_error, "Failed to create the pool metadata LV: ");
    2414            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2415            0 :         g_propagate_error (error, l_error);
    2416            0 :         return FALSE;
    2417              :     }
    2418              : 
    2419              :     /* 2/3 steps done */
    2420            8 :     bd_utils_report_progress (progress_id, 66, "Created the metadata LV");
    2421              : 
    2422              :     /* create the cache pool from the two LVs */
    2423            8 :     args[5] = name;
    2424            8 :     args[7] = (const gchar *) bd_lvm_cache_get_mode_str (mode, &l_error);
    2425            8 :     if (!args[7]) {
    2426            0 :         g_free ((gchar *) args[5]);
    2427            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2428            0 :         g_propagate_error (error, l_error);
    2429            0 :         return FALSE;
    2430              :     }
    2431            8 :     name = g_strdup_printf ("%s/%s", vg_name, pool_name);
    2432            8 :     args[8] = name;
    2433            8 :     success = call_lvm_and_report_error (args, NULL, TRUE, &l_error);
    2434            8 :     g_free ((gchar *) args[5]);
    2435            8 :     g_free ((gchar *) args[8]);
    2436              : 
    2437            8 :     if (!success) {
    2438            0 :         if (l_error)
    2439            0 :             bd_utils_report_finished (progress_id, l_error->message);
    2440              :         else
    2441            0 :             bd_utils_report_finished (progress_id, "Completed");
    2442            0 :         g_propagate_error (error, l_error);
    2443              :     } else
    2444            8 :         bd_utils_report_finished (progress_id, "Completed");
    2445              : 
    2446              :     /* just return the result of the last step (it sets error on fail) */
    2447            8 :     return success;
    2448              : }
    2449              : 
    2450              : /**
    2451              :  * bd_lvm_cache_attach:
    2452              :  * @vg_name: name of the VG containing the @data_lv and the @cache_pool_lv LVs
    2453              :  * @data_lv: data LV to attach the @cache_pool_lv to
    2454              :  * @cache_pool_lv: cache pool LV to attach to the @data_lv
    2455              :  * @extra: (nullable) (array zero-terminated=1): extra options for the cache attachment
    2456              :  *                                                 (just passed to LVM as is)
    2457              :  * @error: (out) (optional): place to store error (if any)
    2458              :  *
    2459              :  * Returns: whether the @cache_pool_lv was successfully attached to the @data_lv or not
    2460              :  *
    2461              :  * Note: Both @data_lv and @cache_lv will be deactivated before the operation.
    2462              :  *
    2463              :  * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_MODIFY
    2464              :  */
    2465            6 : gboolean bd_lvm_cache_attach (const gchar *vg_name, const gchar *data_lv, const gchar *cache_pool_lv, const BDExtraArg **extra, GError **error) {
    2466            6 :     const gchar *args[8] = {"lvconvert", "-y", "--type", "cache", "--cachepool", NULL, NULL, NULL};
    2467            6 :     gboolean success = FALSE;
    2468              : 
    2469            6 :     args[5] = g_strdup_printf ("%s/%s", vg_name, cache_pool_lv);
    2470            6 :     args[6] = g_strdup_printf ("%s/%s", vg_name, data_lv);
    2471            6 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    2472              : 
    2473            6 :     g_free ((gchar *) args[5]);
    2474            6 :     g_free ((gchar *) args[6]);
    2475            6 :     return success;
    2476              : }
    2477              : 
    2478              : /**
    2479              :  * bd_lvm_cache_detach:
    2480              :  * @vg_name: name of the VG containing the @cached_lv
    2481              :  * @cached_lv: name of the cached LV to detach its cache from
    2482              :  * @destroy: whether to destroy the cache after detach or not
    2483              :  * @extra: (nullable) (array zero-terminated=1): extra options for the cache detachment
    2484              :  *                                                 (just passed to LVM as is)
    2485              :  * @error: (out) (optional): place to store error (if any)
    2486              :  *
    2487              :  * Returns: whether the cache was successfully detached from the @cached_lv or not
    2488              :  *
    2489              :  * Note: synces the cache first
    2490              :  *
    2491              :  * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_MODIFY
    2492              :  */
    2493            4 : gboolean bd_lvm_cache_detach (const gchar *vg_name, const gchar *cached_lv, gboolean destroy, const BDExtraArg **extra, GError **error) {
    2494              :     /* need to both "assume yes" and "force" to get rid of the interactive
    2495              :        questions in case of "--uncache" */
    2496            4 :     const gchar *args[6] = {"lvconvert", "-y", "-f", NULL, NULL, NULL};
    2497            4 :     gboolean success = FALSE;
    2498              : 
    2499            4 :     args[3] = destroy ? "--uncache" : "--splitcache";
    2500            4 :     args[4] = g_strdup_printf ("%s/%s", vg_name, cached_lv);
    2501            4 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    2502              : 
    2503            4 :     g_free ((gchar *) args[4]);
    2504            4 :     return success;
    2505              : }
    2506              : 
    2507              : /**
    2508              :  * bd_lvm_cache_create_cached_lv:
    2509              :  * @vg_name: name of the VG to create a cached LV in
    2510              :  * @lv_name: name of the cached LV to create
    2511              :  * @data_size: size of the data LV
    2512              :  * @cache_size: size of the cache (or cached LV more precisely)
    2513              :  * @md_size: size of the cache metadata LV or 0 to use the default
    2514              :  * @mode: cache mode for the cached LV
    2515              :  * @flags: a combination of (ORed) #BDLVMCachePoolFlags
    2516              :  * @slow_pvs: (array zero-terminated=1): list of slow PVs (used for the data LV)
    2517              :  * @fast_pvs: (array zero-terminated=1): list of fast PVs (used for the cache LV)
    2518              :  * @error: (out) (optional): place to store error (if any)
    2519              :  *
    2520              :  * Returns: whether the cached LV @lv_name was successfully created or not
    2521              :  *
    2522              :  * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_CREATE
    2523              :  */
    2524            1 : gboolean bd_lvm_cache_create_cached_lv (const gchar *vg_name, const gchar *lv_name, guint64 data_size, guint64 cache_size, guint64 md_size, BDLVMCacheMode mode, BDLVMCachePoolFlags flags,
    2525              :                                         const gchar **slow_pvs, const gchar **fast_pvs, GError **error) {
    2526            1 :     gboolean success = FALSE;
    2527            1 :     gchar *name = NULL;
    2528            1 :     gchar *msg = NULL;
    2529            1 :     guint64 progress_id = 0;
    2530            1 :     GError *l_error = NULL;
    2531              : 
    2532            1 :     msg = g_strdup_printf ("Started 'create cached LV %s/%s'", vg_name, lv_name);
    2533            1 :     progress_id = bd_utils_report_started (msg);
    2534            1 :     g_free (msg);
    2535              : 
    2536            1 :     name = g_strdup_printf ("%s_cache", lv_name);
    2537            1 :     success = bd_lvm_cache_create_pool (vg_name, name, cache_size, md_size, mode, flags, fast_pvs, &l_error);
    2538            1 :     if (!success) {
    2539            0 :         g_prefix_error (&l_error, "Failed to create the cache pool '%s': ", name);
    2540            0 :         g_free (name);
    2541            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2542            0 :         g_propagate_error (error, l_error);
    2543            0 :         return FALSE;
    2544              :     }
    2545              : 
    2546              :     /* 3/5 steps (cache pool creation has 3 steps) done */
    2547            1 :     bd_utils_report_progress (progress_id, 60, "Cache pool created");
    2548              : 
    2549            1 :     success = bd_lvm_lvcreate (vg_name, lv_name, data_size, NULL, slow_pvs, NULL, &l_error);
    2550            1 :     if (!success) {
    2551            0 :         g_free (name);
    2552            0 :         g_prefix_error (&l_error, "Failed to create the data LV: ");
    2553            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2554            0 :         g_propagate_error (error, l_error);
    2555            0 :         return FALSE;
    2556              :     }
    2557              : 
    2558              :     /* 4/5 steps (cache pool creation has 3 steps) done */
    2559            1 :     bd_utils_report_progress (progress_id, 80, "Data LV created");
    2560              : 
    2561            1 :     success = bd_lvm_cache_attach (vg_name, lv_name, name, NULL, &l_error);
    2562            1 :     if (!success) {
    2563            0 :         g_prefix_error (error, "Failed to attach the cache pool '%s' to the data LV: ", name);
    2564            0 :         g_free (name);
    2565            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2566            0 :         g_propagate_error (error, l_error);
    2567            0 :         return FALSE;
    2568              :     }
    2569              : 
    2570            1 :     bd_utils_report_finished (progress_id, "Completed");
    2571            1 :     g_free (name);
    2572            1 :     return TRUE;
    2573              : }
    2574              : 
    2575              : /**
    2576              :  * bd_lvm_writecache_attach:
    2577              :  * @vg_name: name of the VG containing the @data_lv and the @cache_pool_lv LVs
    2578              :  * @data_lv: data LV to attach the @cache_lv to
    2579              :  * @cache_lv: cache (fast) LV to attach to the @data_lv
    2580              :  * @extra: (nullable) (array zero-terminated=1): extra options for the cache attachment
    2581              :  *                                                 (just passed to LVM as is)
    2582              :  * @error: (out) (optional): place to store error (if any)
    2583              :  *
    2584              :  * Returns: whether the @cache_lv was successfully attached to the @data_lv or not
    2585              :  *
    2586              :  * Tech category: %BD_LVM_TECH_WRITECACHE-%BD_LVM_TECH_MODE_MODIFY
    2587              :  */
    2588            3 : gboolean bd_lvm_writecache_attach (const gchar *vg_name, const gchar *data_lv, const gchar *cache_lv, const BDExtraArg **extra, GError **error) {
    2589            3 :     const gchar *args[8] = {"lvconvert", "-y", "--type", "writecache", "--cachevol", NULL, NULL, NULL};
    2590            3 :     gboolean success = FALSE;
    2591              : 
    2592              :     /* both LVs need to be inactive for the writecache convert to work */
    2593            3 :     success = bd_lvm_lvdeactivate (vg_name, data_lv, NULL, error);
    2594            3 :     if (!success)
    2595            0 :         return FALSE;
    2596              : 
    2597            3 :     success = bd_lvm_lvdeactivate (vg_name, cache_lv, NULL, error);
    2598            3 :     if (!success)
    2599            0 :         return FALSE;
    2600              : 
    2601            3 :     args[5] = g_strdup_printf ("%s/%s", vg_name, cache_lv);
    2602            3 :     args[6] = g_strdup_printf ("%s/%s", vg_name, data_lv);
    2603            3 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    2604              : 
    2605            3 :     g_free ((gchar *) args[5]);
    2606            3 :     g_free ((gchar *) args[6]);
    2607            3 :     return success;
    2608              : }
    2609              : 
    2610              : /**
    2611              :  * bd_lvm_writecache_detach:
    2612              :  * @vg_name: name of the VG containing the @cached_lv
    2613              :  * @cached_lv: name of the cached LV to detach its cache from
    2614              :  * @destroy: whether to destroy the cache after detach or not
    2615              :  * @extra: (nullable) (array zero-terminated=1): extra options for the cache detachment
    2616              :  *                                                 (just passed to LVM as is)
    2617              :  * @error: (out) (optional): place to store error (if any)
    2618              :  *
    2619              :  * Returns: whether the cache was successfully detached from the @cached_lv or not
    2620              :  *
    2621              :  * Note: synces the cache first
    2622              :  *
    2623              :  * Tech category: %BD_LVM_TECH_WRITECACHE-%BD_LVM_TECH_MODE_MODIFY
    2624              :  */
    2625            2 : gboolean bd_lvm_writecache_detach (const gchar *vg_name, const gchar *cached_lv, gboolean destroy, const BDExtraArg **extra, GError **error) {
    2626            2 :     return bd_lvm_cache_detach (vg_name, cached_lv, destroy, extra, error);
    2627              : }
    2628              : 
    2629              : /**
    2630              :  * bd_lvm_writecache_create_cached_lv:
    2631              :  * @vg_name: name of the VG to create a cached LV in
    2632              :  * @lv_name: name of the cached LV to create
    2633              :  * @data_size: size of the data LV
    2634              :  * @cache_size: size of the cache (or cached LV more precisely)
    2635              :  * @slow_pvs: (array zero-terminated=1): list of slow PVs (used for the data LV)
    2636              :  * @fast_pvs: (array zero-terminated=1): list of fast PVs (used for the cache LV)
    2637              :  * @error: (out) (optional): place to store error (if any)
    2638              :  *
    2639              :  * Returns: whether the cached LV @lv_name was successfully created or not
    2640              :  *
    2641              :  * Tech category: %BD_LVM_TECH_WRITECACHE-%BD_LVM_TECH_MODE_CREATE
    2642              :  */
    2643            1 : gboolean bd_lvm_writecache_create_cached_lv (const gchar *vg_name, const gchar *lv_name, guint64 data_size, guint64 cache_size,
    2644              :                                              const gchar **slow_pvs, const gchar **fast_pvs, GError **error) {
    2645            1 :     gboolean success = FALSE;
    2646            1 :     gchar *name = NULL;
    2647            1 :     gchar *msg = NULL;
    2648            1 :     guint64 progress_id = 0;
    2649            1 :     GError *l_error = NULL;
    2650              : 
    2651            1 :     msg = g_strdup_printf ("Started 'create cached LV %s/%s'", vg_name, lv_name);
    2652            1 :     progress_id = bd_utils_report_started (msg);
    2653            1 :     g_free (msg);
    2654              : 
    2655            1 :     name = g_strdup_printf ("%s_writecache", lv_name);
    2656            1 :     success = bd_lvm_lvcreate (vg_name, name, cache_size, NULL, fast_pvs, NULL, &l_error);
    2657            1 :     if (!success) {
    2658            0 :         g_prefix_error (&l_error, "Failed to create the cache LV '%s': ", name);
    2659            0 :         g_free (name);
    2660            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2661            0 :         g_propagate_error (error, l_error);
    2662            0 :         return FALSE;
    2663              :     }
    2664              : 
    2665              :     /* 1/3 steps done */
    2666            1 :     bd_utils_report_progress (progress_id, 33, "Cache LV created");
    2667              : 
    2668            1 :     success = bd_lvm_lvcreate (vg_name, lv_name, data_size, NULL, slow_pvs, NULL, &l_error);
    2669            1 :     if (!success) {
    2670            0 :         g_free (name);
    2671            0 :         g_prefix_error (&l_error, "Failed to create the data LV: ");
    2672            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2673            0 :         g_propagate_error (error, l_error);
    2674            0 :         return FALSE;
    2675              :     }
    2676              : 
    2677              :     /* 2/3 steps done */
    2678            1 :     bd_utils_report_progress (progress_id, 66, "Data LV created");
    2679              : 
    2680            1 :     success = bd_lvm_writecache_attach (vg_name, lv_name, name, NULL, &l_error);
    2681            1 :     if (!success) {
    2682            0 :         g_prefix_error (&l_error, "Failed to attach the cache LV '%s' to the data LV: ", name);
    2683            0 :         g_free (name);
    2684            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2685            0 :         g_propagate_error (error, l_error);
    2686            0 :         return FALSE;
    2687              :     }
    2688              : 
    2689            1 :     bd_utils_report_finished (progress_id, "Completed");
    2690            1 :     g_free (name);
    2691            1 :     return TRUE;
    2692              : }
    2693              : 
    2694              : /**
    2695              :  * bd_lvm_cache_pool_name:
    2696              :  * @vg_name: name of the VG containing the @cached_lv
    2697              :  * @cached_lv: cached LV to get the name of the its pool LV for
    2698              :  * @error: (out) (optional): place to store error (if any)
    2699              :  *
    2700              :  * Returns: name of the cache pool LV used by the @cached_lv or %NULL in case of error
    2701              :  *
    2702              :  * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_QUERY
    2703              :  */
    2704            1 : gchar* bd_lvm_cache_pool_name (const gchar *vg_name, const gchar *cached_lv, GError **error) {
    2705            1 :     gchar *ret = NULL;
    2706            1 :     gchar *name_start = NULL;
    2707            1 :     gchar *name_end = NULL;
    2708            1 :     gchar *pool_name = NULL;
    2709              : 
    2710              :     /* same as for a thin LV, but with square brackets */
    2711            1 :     ret = bd_lvm_thlvpoolname (vg_name, cached_lv, error);
    2712            1 :     if (!ret)
    2713            0 :         return NULL;
    2714              : 
    2715            1 :     name_start = strchr (ret, '[');
    2716            1 :     if (!name_start) {
    2717            0 :         g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_CACHE_INVAL,
    2718              :                      "Failed to determine cache pool name from: '%s'", ret);
    2719            0 :         g_free (ret);
    2720            0 :         return NULL;
    2721              :     }
    2722            1 :     name_start++;
    2723              : 
    2724            1 :     name_end = strchr (ret, ']');
    2725            1 :     if (!name_end) {
    2726            0 :         g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_CACHE_INVAL,
    2727              :                      "Failed to determine cache pool name from: '%s'", ret);
    2728            0 :         g_free (ret);
    2729            0 :         return NULL;
    2730              :     }
    2731              : 
    2732            1 :     pool_name = g_strndup (name_start, name_end - name_start);
    2733            1 :     g_free (ret);
    2734              : 
    2735            1 :     return pool_name;
    2736              : }
    2737              : 
    2738              : /**
    2739              :  * bd_lvm_thpool_convert:
    2740              :  * @vg_name: name of the VG to create the new thin pool in
    2741              :  * @data_lv: name of the LV that should become the data part of the new pool
    2742              :  * @metadata_lv: name of the LV that should become the metadata part of the new pool
    2743              :  * @name: (nullable): name for the thin pool (if %NULL, the name @data_lv is inherited)
    2744              :  * @extra: (nullable) (array zero-terminated=1): extra options for the thin pool creation
    2745              :  *                                                 (just passed to LVM as is)
    2746              :  * @error: (out) (optional): place to store error (if any)
    2747              :  *
    2748              :  * Converts the @data_lv and @metadata_lv into a new thin pool in the @vg_name
    2749              :  * VG.
    2750              :  *
    2751              :  * Returns: whether the new thin pool was successfully created from @data_lv and
    2752              :  *          @metadata_lv or not
    2753              :  *
    2754              :  * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_CREATE
    2755              :  */
    2756            1 : gboolean bd_lvm_thpool_convert (const gchar *vg_name, const gchar *data_lv, const gchar *metadata_lv, const gchar *name, const BDExtraArg **extra, GError **error) {
    2757            1 :     const gchar *args[8] = {"lvconvert", "--yes", "--type", "thin-pool", "--poolmetadata", metadata_lv, NULL, NULL};
    2758            1 :     gboolean success = FALSE;
    2759              : 
    2760            1 :     args[6] = g_strdup_printf ("%s/%s", vg_name, data_lv);
    2761              : 
    2762            1 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    2763            1 :     g_free ((gchar *) args[6]);
    2764              : 
    2765            1 :     if (success && name)
    2766            1 :         success = bd_lvm_lvrename (vg_name, data_lv, name, NULL, error);
    2767              : 
    2768            1 :     return success;
    2769              : }
    2770              : 
    2771              : /**
    2772              :  * bd_lvm_cache_pool_convert:
    2773              :  * @vg_name: name of the VG to create the new thin pool in
    2774              :  * @data_lv: name of the LV that should become the data part of the new pool
    2775              :  * @metadata_lv: name of the LV that should become the metadata part of the new pool
    2776              :  * @name: (nullable): name for the thin pool (if %NULL, the name @data_lv is inherited)
    2777              :  * @extra: (nullable) (array zero-terminated=1): extra options for the thin pool creation
    2778              :  *                                                 (just passed to LVM as is)
    2779              :  * @error: (out) (optional): place to store error (if any)
    2780              :  *
    2781              :  * Converts the @data_lv and @metadata_lv into a new cache pool in the @vg_name
    2782              :  * VG.
    2783              :  *
    2784              :  * Returns: whether the new cache pool was successfully created from @data_lv and
    2785              :  *          @metadata_lv or not
    2786              :  *
    2787              :  * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_CREATE
    2788              :  */
    2789            1 : gboolean bd_lvm_cache_pool_convert (const gchar *vg_name, const gchar *data_lv, const gchar *metadata_lv, const gchar *name, const BDExtraArg **extra, GError **error) {
    2790            1 :     const gchar *args[8] = {"lvconvert", "--yes", "--type", "cache-pool", "--poolmetadata", metadata_lv, NULL, NULL};
    2791            1 :     gboolean success = FALSE;
    2792              : 
    2793            1 :     args[6] = g_strdup_printf ("%s/%s", vg_name, data_lv);
    2794              : 
    2795            1 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    2796            1 :     g_free ((gchar *) args[6]);
    2797              : 
    2798            1 :     if (success && name)
    2799            1 :         success = bd_lvm_lvrename (vg_name, data_lv, name, NULL, error);
    2800              : 
    2801            1 :     return success;
    2802              : }
    2803              : 
    2804              : /**
    2805              :  * bd_lvm_vdo_pool_create:
    2806              :  * @vg_name: name of the VG to create a new LV in
    2807              :  * @lv_name: name of the to-be-created VDO LV
    2808              :  * @pool_name: (nullable): name of the to-be-created VDO pool LV or %NULL for default name
    2809              :  * @data_size: requested size of the data VDO LV (physical size of the @pool_name VDO pool LV)
    2810              :  * @virtual_size: requested virtual_size of the @lv_name VDO LV
    2811              :  * @index_memory: amount of index memory (in bytes) or 0 for default
    2812              :  * @compression: whether to enable compression or not
    2813              :  * @deduplication: whether to enable deduplication or not
    2814              :  * @write_policy: write policy for the volume
    2815              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VDO LV creation
    2816              :  *                                                 (just passed to LVM as is)
    2817              :  * @error: (out) (optional): place to store error (if any)
    2818              :  *
    2819              :  * Returns: whether the given @vg_name/@lv_name VDO LV was successfully created or not
    2820              :  *
    2821              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_CREATE
    2822              :  */
    2823            7 : gboolean bd_lvm_vdo_pool_create (const gchar *vg_name, const gchar *lv_name, const gchar *pool_name, guint64 data_size, guint64 virtual_size, guint64 index_memory, gboolean compression, gboolean deduplication, BDLVMVDOWritePolicy write_policy, const BDExtraArg **extra, GError **error) {
    2824            7 :     const gchar *args[16] = {"lvcreate", "--type", "vdo", "-n", lv_name, "-L", NULL, "-V", NULL,
    2825              :                              "--compression", compression ? "y" : "n",
    2826              :                              "--deduplication", deduplication ? "y" : "n",
    2827              :                              "-y", NULL, NULL};
    2828            7 :     gboolean success = FALSE;
    2829            7 :     gchar *old_config = NULL;
    2830            7 :     const gchar *write_policy_str = NULL;
    2831              : 
    2832            7 :     write_policy_str = bd_lvm_get_vdo_write_policy_str (write_policy, error);
    2833            7 :     if (!write_policy_str)
    2834            0 :         return FALSE;
    2835              : 
    2836            7 :     args[6] = g_strdup_printf ("%"G_GUINT64_FORMAT"K", data_size / 1024);
    2837            7 :     args[8] = g_strdup_printf ("%"G_GUINT64_FORMAT"K", virtual_size / 1024);
    2838              : 
    2839            7 :     if (pool_name) {
    2840            6 :         args[14] = g_strdup_printf ("%s/%s", vg_name, pool_name);
    2841              :     } else
    2842            1 :         args[14] = vg_name;
    2843              : 
    2844              :     /* index_memory and write_policy can be specified only using the config */
    2845            7 :     g_mutex_lock (&global_config_lock);
    2846            7 :     old_config = global_config_str;
    2847            7 :     if (index_memory != 0)
    2848            3 :         global_config_str = g_strdup_printf ("%s allocation {vdo_index_memory_size_mb=%"G_GUINT64_FORMAT" vdo_write_policy=\"%s\"}", old_config ? old_config : "",
    2849              :                                                                                                                                      index_memory / (1024 * 1024),
    2850              :                                                                                                                                      write_policy_str);
    2851              :     else
    2852            4 :         global_config_str = g_strdup_printf ("%s allocation {vdo_write_policy=\"%s\"}", old_config ? old_config : "",
    2853              :                                                                                         write_policy_str);
    2854              : 
    2855            7 :     success = call_lvm_and_report_error (args, extra, FALSE, error);
    2856              : 
    2857            7 :     g_free (global_config_str);
    2858            7 :     global_config_str = old_config;
    2859            7 :     g_mutex_unlock (&global_config_lock);
    2860              : 
    2861            7 :     g_free ((gchar *) args[6]);
    2862            7 :     g_free ((gchar *) args[8]);
    2863              : 
    2864            7 :     if (pool_name)
    2865            6 :         g_free ((gchar *) args[14]);
    2866              : 
    2867            7 :     return success;
    2868              : }
    2869              : 
    2870            4 : static gboolean _vdo_set_compression_deduplication (const gchar *vg_name, const gchar *pool_name, const gchar *op, gboolean enable, const BDExtraArg **extra, GError **error) {
    2871            4 :     const gchar *args[5] = {"lvchange", op, enable ? "y" : "n", NULL, NULL};
    2872            4 :     gboolean success = FALSE;
    2873              : 
    2874            4 :     args[3] = g_strdup_printf ("%s/%s", vg_name, pool_name);
    2875              : 
    2876            4 :     success = call_lvm_and_report_error (args, extra, TRUE, error);
    2877            4 :     g_free ((gchar *) args[3]);
    2878              : 
    2879            4 :     return success;
    2880              : }
    2881              : 
    2882              : /**
    2883              :  * bd_lvm_vdo_enable_compression:
    2884              :  * @vg_name: name of the VG containing the to-be-changed VDO pool LV
    2885              :  * @pool_name: name of the VDO pool LV to enable compression on
    2886              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VDO change
    2887              :  *                                                 (just passed to LVM as is)
    2888              :  * @error: (out) (optional): place to store error (if any)
    2889              :  *
    2890              :  * Returns: whether compression was successfully enabled on @vg_name/@pool_name LV or not
    2891              :  *
    2892              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
    2893              :  */
    2894            1 : gboolean bd_lvm_vdo_enable_compression (const gchar *vg_name, const gchar *pool_name, const BDExtraArg **extra, GError **error) {
    2895            1 :     return _vdo_set_compression_deduplication (vg_name, pool_name, "--compression", TRUE, extra, error);
    2896              : }
    2897              : 
    2898              : /**
    2899              :  * bd_lvm_vdo_disable_compression:
    2900              :  * @vg_name: name of the VG containing the to-be-changed VDO pool LV
    2901              :  * @pool_name: name of the VDO pool LV to disable compression on
    2902              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VDO change
    2903              :  *                                                 (just passed to LVM as is)
    2904              :  * @error: (out) (optional): place to store error (if any)
    2905              :  *
    2906              :  * Returns: whether compression was successfully disabled on @vg_name/@pool_name LV or not
    2907              :  *
    2908              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
    2909              :  */
    2910            1 : gboolean bd_lvm_vdo_disable_compression (const gchar *vg_name, const gchar *pool_name, const BDExtraArg **extra, GError **error) {
    2911            1 :     return _vdo_set_compression_deduplication (vg_name, pool_name, "--compression", FALSE, extra, error);
    2912              : }
    2913              : 
    2914              : /**
    2915              :  * bd_lvm_vdo_enable_deduplication:
    2916              :  * @vg_name: name of the VG containing the to-be-changed VDO pool LV
    2917              :  * @pool_name: name of the VDO pool LV to enable deduplication on
    2918              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VDO change
    2919              :  *                                                 (just passed to LVM as is)
    2920              :  * @error: (out) (optional): place to store error (if any)
    2921              :  *
    2922              :  * Returns: whether deduplication was successfully enabled on @vg_name/@pool_name LV or not
    2923              :  *
    2924              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
    2925              :  */
    2926            1 : gboolean bd_lvm_vdo_enable_deduplication (const gchar *vg_name, const gchar *pool_name, const BDExtraArg **extra, GError **error) {
    2927            1 :     return _vdo_set_compression_deduplication (vg_name, pool_name, "--deduplication", TRUE, extra, error);
    2928              : }
    2929              : 
    2930              : /**
    2931              :  * bd_lvm_vdo_enable_deduplication:
    2932              :  * @vg_name: name of the VG containing the to-be-changed VDO pool LV
    2933              :  * @pool_name: name of the VDO pool LV to disable deduplication on
    2934              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VDO change
    2935              :  *                                                 (just passed to LVM as is)
    2936              :  * @error: (out) (optional): place to store error (if any)
    2937              :  *
    2938              :  * Returns: whether deduplication was successfully disabled on @vg_name/@pool_name LV or not
    2939              :  *
    2940              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
    2941              :  */
    2942            1 : gboolean bd_lvm_vdo_disable_deduplication (const gchar *vg_name, const gchar *pool_name, const BDExtraArg **extra, GError **error) {
    2943            1 :     return _vdo_set_compression_deduplication (vg_name, pool_name, "--deduplication", FALSE, extra, error);
    2944              : }
    2945              : 
    2946              : /**
    2947              :  * bd_lvm_vdo_info:
    2948              :  * @vg_name: name of the VG that contains the LV to get information about
    2949              :  * @lv_name: name of the LV to get information about
    2950              :  * @error: (out) (optional): place to store error (if any)
    2951              :  *
    2952              :  * Returns: (transfer full): information about the @vg_name/@lv_name LV or %NULL in case
    2953              :  * of error (the @error) gets populated in those cases)
    2954              :  *
    2955              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_QUERY
    2956              :  */
    2957           10 : BDLVMVDOPooldata* bd_lvm_vdo_info (const gchar *vg_name, const gchar *lv_name, GError **error) {
    2958           10 :     const gchar *args[11] = {"lvs", "--noheadings", "--nosuffix", "--nameprefixes",
    2959              :                        "--unquoted", "--units=b", "-a",
    2960              :                        "-o", "vdo_operating_mode,vdo_compression_state,vdo_index_state,vdo_write_policy,vdo_index_memory_size,vdo_used_size,vdo_saving_percent,vdo_compression,vdo_deduplication",
    2961              :                        NULL, NULL};
    2962              : 
    2963           10 :     GHashTable *table = NULL;
    2964           10 :     gboolean success = FALSE;
    2965           10 :     gchar *output = NULL;
    2966           10 :     gchar **lines = NULL;
    2967           10 :     gchar **lines_p = NULL;
    2968              :     guint num_items;
    2969              : 
    2970           10 :     args[9] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    2971              : 
    2972           10 :     success = call_lvm_and_capture_output (args, NULL, &output, error);
    2973           10 :     g_free ((gchar *) args[9]);
    2974              : 
    2975           10 :     if (!success)
    2976              :         /* the error is already populated from the call */
    2977            0 :         return NULL;
    2978              : 
    2979           10 :     lines = g_strsplit (output, "\n", 0);
    2980           10 :     g_free (output);
    2981              : 
    2982           10 :     for (lines_p = lines; *lines_p; lines_p++) {
    2983           10 :         table = parse_lvm_vars ((*lines_p), &num_items);
    2984           10 :         if (table && (num_items == 9)) {
    2985           10 :             g_strfreev (lines);
    2986           10 :             return get_vdo_data_from_table (table, TRUE);
    2987            0 :         } else if (table)
    2988            0 :             g_hash_table_destroy (table);
    2989              :     }
    2990            0 :     g_strfreev (lines);
    2991              : 
    2992              :     /* getting here means no usable info was found */
    2993            0 :     g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
    2994              :                  "Failed to parse information about the VDO LV");
    2995            0 :     return NULL;
    2996              : }
    2997              : 
    2998              : /**
    2999              :  * bd_lvm_vdo_resize:
    3000              :  * @vg_name: name of the VG containing the to-be-resized VDO LV
    3001              :  * @lv_name: name of the to-be-resized VDO LV
    3002              :  * @size: the requested new size of the VDO LV
    3003              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VDO LV resize
    3004              :  *                                                 (just passed to LVM as is)
    3005              :  * @error: (out) (optional): place to store error (if any)
    3006              :  *
    3007              :  * Returns: whether the @vg_name/@lv_name VDO LV was successfully resized or not
    3008              :  *
    3009              :  * Note: Reduction needs to process TRIM for reduced disk area to unmap used data blocks
    3010              :  *       from the VDO pool LV and it may take a long time.
    3011              :  *
    3012              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
    3013              :  */
    3014            1 : gboolean bd_lvm_vdo_resize (const gchar *vg_name, const gchar *lv_name, guint64 size, const BDExtraArg **extra, GError **error) {
    3015            1 :     return bd_lvm_lvresize (vg_name, lv_name, size, extra, error);
    3016              : }
    3017              : 
    3018              : /**
    3019              :  * bd_lvm_vdo_pool_resize:
    3020              :  * @vg_name: name of the VG containing the to-be-resized VDO pool LV
    3021              :  * @pool_name: name of the to-be-resized VDO pool LV
    3022              :  * @size: the requested new size of the VDO pool LV
    3023              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VDO pool LV resize
    3024              :  *                                                 (just passed to LVM as is)
    3025              :  * @error: (out) (optional): place to store error (if any)
    3026              :  *
    3027              :  * Returns: whether the @vg_name/@pool_name VDO pool LV was successfully resized or not
    3028              :  *
    3029              :  * Note: Size of the VDO pool LV can be only extended, not reduced.
    3030              :  *
    3031              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
    3032              :  */
    3033            2 : gboolean bd_lvm_vdo_pool_resize (const gchar *vg_name, const gchar *pool_name, guint64 size, const BDExtraArg **extra, GError **error) {
    3034            2 :     BDLVMLVdata *info = NULL;
    3035              : 
    3036            2 :     info = bd_lvm_lvinfo (vg_name, pool_name, error);
    3037            2 :     if (!info)
    3038            0 :         return FALSE;
    3039              : 
    3040            2 :     if (info->size >= size) {
    3041            1 :         g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOT_SUPPORTED,
    3042              :                      "Reducing physical size of the VDO pool LV is not supported.");
    3043            1 :         bd_lvm_lvdata_free (info);
    3044            1 :         return FALSE;
    3045              :     }
    3046              : 
    3047            1 :     bd_lvm_lvdata_free (info);
    3048              : 
    3049            1 :     return bd_lvm_lvresize (vg_name, pool_name, size, extra, error);
    3050              : }
    3051              : 
    3052              : /**
    3053              :  * bd_lvm_vdo_pool_convert:
    3054              :  * @vg_name: name of the VG that contains @pool_lv
    3055              :  * @pool_lv: name of the LV that should become the new VDO pool LV
    3056              :  * @name: (nullable): name for the VDO LV or %NULL for default name
    3057              :  * @virtual_size: virtual size for the new VDO LV
    3058              :  * @index_memory: amount of index memory (in bytes) or 0 for default
    3059              :  * @compression: whether to enable compression or not
    3060              :  * @deduplication: whether to enable deduplication or not
    3061              :  * @write_policy: write policy for the volume
    3062              :  * @extra: (nullable) (array zero-terminated=1): extra options for the VDO pool creation
    3063              :  *                                                 (just passed to LVM as is)
    3064              :  * @error: (out) (optional): place to store error (if any)
    3065              :  *
    3066              :  * Converts the @pool_lv into a new VDO pool LV in the @vg_name VG and creates a new
    3067              :  * @name VDO LV with size @virtual_size.
    3068              :  *
    3069              :  * Note: All data on @pool_lv will be irreversibly destroyed.
    3070              :  *
    3071              :  * Returns: whether the new VDO pool LV was successfully created from @pool_lv and or not
    3072              :  *
    3073              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_CREATE&%BD_LVM_TECH_MODE_MODIFY
    3074              :  */
    3075            1 : gboolean bd_lvm_vdo_pool_convert (const gchar *vg_name, const gchar *pool_lv, const gchar *name, guint64 virtual_size, guint64 index_memory, gboolean compression, gboolean deduplication, BDLVMVDOWritePolicy write_policy, const BDExtraArg **extra, GError **error) {
    3076            1 :     const gchar *args[14] = {"lvconvert", "--yes", "--type", "vdo-pool",
    3077              :                              "--compression", compression ? "y" : "n",
    3078              :                              "--deduplication", deduplication ? "y" : "n",
    3079              :                              NULL, NULL, NULL, NULL, NULL, NULL};
    3080            1 :     gboolean success = FALSE;
    3081            1 :     guint next_arg = 4;
    3082            1 :     gchar *size_str = NULL;
    3083            1 :     gchar *lv_spec = NULL;
    3084            1 :     gchar *old_config = NULL;
    3085            1 :     const gchar *write_policy_str = NULL;
    3086              : 
    3087            1 :     write_policy_str = bd_lvm_get_vdo_write_policy_str (write_policy, error);
    3088            1 :     if (!write_policy_str)
    3089            0 :         return FALSE;
    3090              : 
    3091            1 :     if (name) {
    3092            1 :         args[next_arg++] = "-n";
    3093            1 :         args[next_arg++] = name;
    3094              :     }
    3095              : 
    3096            1 :     args[next_arg++] = "-V";
    3097            1 :     size_str = g_strdup_printf ("%"G_GUINT64_FORMAT"K", virtual_size / 1024);
    3098            1 :     args[next_arg++] = size_str;
    3099            1 :     lv_spec = g_strdup_printf ("%s/%s", vg_name, pool_lv);
    3100            1 :     args[next_arg++] = lv_spec;
    3101              : 
    3102              :     /* index_memory and write_policy can be specified only using the config */
    3103            1 :     g_mutex_lock (&global_config_lock);
    3104            1 :     old_config = global_config_str;
    3105            1 :     if (index_memory != 0)
    3106            0 :         global_config_str = g_strdup_printf ("%s allocation {vdo_index_memory_size_mb=%"G_GUINT64_FORMAT" vdo_write_policy=\"%s\"}", old_config ? old_config : "",
    3107              :                                                                                                                                      index_memory / (1024 * 1024),
    3108              :                                                                                                                                      write_policy_str);
    3109              :     else
    3110            1 :         global_config_str = g_strdup_printf ("%s allocation {vdo_write_policy=\"%s\"}", old_config ? old_config : "",
    3111              :                                                                                         write_policy_str);
    3112              : 
    3113            1 :     success = call_lvm_and_report_error (args, extra, FALSE, error);
    3114              : 
    3115            1 :     g_free (global_config_str);
    3116            1 :     global_config_str = old_config;
    3117            1 :     g_mutex_unlock (&global_config_lock);
    3118              : 
    3119            1 :     g_free (size_str);
    3120            1 :     g_free (lv_spec);
    3121              : 
    3122            1 :     return success;
    3123              : }
    3124              : 
    3125              : /**
    3126              :  * bd_lvm_vdolvpoolname:
    3127              :  * @vg_name: name of the VG containing the queried VDO LV
    3128              :  * @lv_name: name of the queried VDO LV
    3129              :  * @error: (out) (optional): place to store error (if any)
    3130              :  *
    3131              :  * Returns: (transfer full): the name of the pool volume for the @vg_name/@lv_name
    3132              :  * VDO LV or %NULL if failed to determine (@error) is set in those cases)
    3133              :  *
    3134              :  * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_QUERY
    3135              :  */
    3136            2 : gchar* bd_lvm_vdolvpoolname (const gchar *vg_name, const gchar *lv_name, GError **error) {
    3137            2 :     gboolean success = FALSE;
    3138            2 :     gchar *output = NULL;
    3139            2 :     const gchar *args[6] = {"lvs", "--noheadings", "-o", "pool_lv", NULL, NULL};
    3140            2 :     args[4] = g_strdup_printf ("%s/%s", vg_name, lv_name);
    3141              : 
    3142            2 :     success = call_lvm_and_capture_output (args, NULL, &output, error);
    3143            2 :     g_free ((gchar *) args[4]);
    3144              : 
    3145            2 :     if (!success)
    3146              :         /* the error is already populated from the call */
    3147            0 :         return NULL;
    3148              : 
    3149            2 :     return g_strstrip (output);
    3150              : }
        

Generated by: LCOV version 2.0-1