Line data Source code
1 : /*
2 : * Copyright (C) 2015-2016 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 <gio/gio.h>
26 : #include <libdevmapper.h>
27 :
28 : #include "lvm.h"
29 : #include "lvm-private.h"
30 : #include "check_deps.h"
31 : #include "dm_logging.h"
32 : #include "vdo_stats.h"
33 :
34 : #define LVM_BUS_NAME "com.redhat.lvmdbus1"
35 : #define LVM_OBJ_PREFIX "/com/redhat/lvmdbus1"
36 : #define MANAGER_OBJ "/com/redhat/lvmdbus1/Manager"
37 : #define MANAGER_INTF "com.redhat.lvmdbus1.Manager"
38 : #define JOB_OBJ_PREFIX "/com/redhat/lvmdbus1/Job/"
39 : #define JOB_INTF "com.redhat.lvmdbus1.Job"
40 : #define PV_OBJ_PREFIX LVM_OBJ_PREFIX"/Pv"
41 : #define VG_OBJ_PREFIX LVM_OBJ_PREFIX"/Vg"
42 : #define LV_OBJ_PREFIX LVM_OBJ_PREFIX"/Lv"
43 : #define HIDDEN_LV_OBJ_PREFIX LVM_OBJ_PREFIX"/HiddenLv"
44 : #define THIN_POOL_OBJ_PREFIX LVM_OBJ_PREFIX"/ThinPool"
45 : #define CACHE_POOL_OBJ_PREFIX LVM_OBJ_PREFIX"/CachePool"
46 : #define VDO_POOL_OBJ_PREFIX LVM_OBJ_PREFIX"/VdoPool"
47 : #define PV_INTF LVM_BUS_NAME".Pv"
48 : #define VG_INTF LVM_BUS_NAME".Vg"
49 : #define VG_VDO_INTF LVM_BUS_NAME".VgVdo"
50 : #define LV_CMN_INTF LVM_BUS_NAME".LvCommon"
51 : #define LV_INTF LVM_BUS_NAME".Lv"
52 : #define CACHED_LV_INTF LVM_BUS_NAME".CachedLv"
53 : #define SNAP_INTF LVM_BUS_NAME".Snapshot"
54 : #define THPOOL_INTF LVM_BUS_NAME".ThinPool"
55 : #define CACHE_POOL_INTF LVM_BUS_NAME".CachePool"
56 : #define VDO_POOL_INTF LVM_BUS_NAME".VdoPool"
57 : #define DBUS_PROPS_IFACE "org.freedesktop.DBus.Properties"
58 : #define DBUS_INTRO_IFACE "org.freedesktop.DBus.Introspectable"
59 : #define METHOD_CALL_TIMEOUT 5000
60 : #define PROGRESS_WAIT 500 * 1000 /* microseconds */
61 :
62 :
63 : static GDBusConnection *bus = NULL;
64 :
65 : /**
66 : * SECTION: lvm
67 : * @short_description: plugin for operations with LVM
68 : * @title: LVM
69 : * @include: lvm.h
70 : *
71 : * A plugin for operations with LVM. All sizes passed in/out to/from
72 : * the functions are in bytes.
73 : */
74 :
75 : /**
76 : * bd_lvm_error_quark: (skip)
77 : */
78 0 : GQuark bd_lvm_error_quark (void)
79 : {
80 0 : return g_quark_from_static_string ("g-bd-lvm-error-quark");
81 : }
82 :
83 0 : BDLVMPVdata* bd_lvm_pvdata_copy (BDLVMPVdata *data) {
84 0 : if (data == NULL)
85 0 : return NULL;
86 :
87 0 : BDLVMPVdata *new_data = g_new0 (BDLVMPVdata, 1);
88 :
89 0 : new_data->pv_name = g_strdup (data->pv_name);
90 0 : new_data->pv_uuid = g_strdup (data->pv_uuid);
91 0 : new_data->pv_free = data->pv_free;
92 0 : new_data->pv_size = data->pv_size;
93 0 : new_data->pe_start = data->pe_start;
94 0 : new_data->vg_name = g_strdup (data->vg_name);
95 0 : new_data->vg_uuid = g_strdup (data->vg_uuid);
96 0 : new_data->vg_size = data->vg_size;
97 0 : new_data->vg_free = data->vg_free;
98 0 : new_data->vg_extent_size = data->vg_extent_size;
99 0 : new_data->vg_extent_count = data->vg_extent_count;
100 0 : new_data->vg_free_count = data->vg_free_count;
101 0 : new_data->vg_pv_count = data->vg_pv_count;
102 0 : new_data->pv_tags = g_strdupv (data->pv_tags);
103 :
104 0 : return new_data;
105 : }
106 :
107 0 : void bd_lvm_pvdata_free (BDLVMPVdata *data) {
108 0 : if (data == NULL)
109 0 : return;
110 :
111 0 : g_free (data->pv_name);
112 0 : g_free (data->pv_uuid);
113 0 : g_free (data->vg_name);
114 0 : g_free (data->vg_uuid);
115 0 : g_strfreev (data->pv_tags);
116 0 : g_free (data);
117 : }
118 :
119 0 : BDLVMVGdata* bd_lvm_vgdata_copy (BDLVMVGdata *data) {
120 0 : if (data == NULL)
121 0 : return NULL;
122 :
123 0 : BDLVMVGdata *new_data = g_new0 (BDLVMVGdata, 1);
124 :
125 0 : new_data->name = g_strdup (data->name);
126 0 : new_data->uuid = g_strdup (data->uuid);
127 0 : new_data->size = data->size;
128 0 : new_data->free = data->free;
129 0 : new_data->extent_size = data->extent_size;
130 0 : new_data->extent_count = data->extent_count;
131 0 : new_data->free_count = data->free_count;
132 0 : new_data->pv_count = data->pv_count;
133 0 : new_data->vg_tags = g_strdupv (data->vg_tags);
134 0 : return new_data;
135 : }
136 :
137 0 : void bd_lvm_vgdata_free (BDLVMVGdata *data) {
138 0 : if (data == NULL)
139 0 : return;
140 :
141 0 : g_free (data->name);
142 0 : g_free (data->uuid);
143 0 : g_strfreev (data->vg_tags);
144 0 : g_free (data);
145 : }
146 :
147 0 : BDLVMLVdata* bd_lvm_lvdata_copy (BDLVMLVdata *data) {
148 0 : if (data == NULL)
149 0 : return NULL;
150 :
151 0 : BDLVMLVdata *new_data = g_new0 (BDLVMLVdata, 1);
152 :
153 0 : new_data->lv_name = g_strdup (data->lv_name);
154 0 : new_data->vg_name = g_strdup (data->vg_name);
155 0 : new_data->uuid = g_strdup (data->uuid);
156 0 : new_data->size = data->size;
157 0 : new_data->attr = g_strdup (data->attr);
158 0 : new_data->segtype = g_strdup (data->segtype);
159 0 : new_data->origin = g_strdup (data->origin);
160 0 : new_data->pool_lv = g_strdup (data->pool_lv);
161 0 : new_data->data_lv = g_strdup (data->data_lv);
162 0 : new_data->metadata_lv = g_strdup (data->metadata_lv);
163 0 : new_data->roles = g_strdup (data->roles);
164 0 : new_data->move_pv = g_strdup (data->move_pv);
165 0 : new_data->data_percent = data->data_percent;
166 0 : new_data->metadata_percent = data->metadata_percent;
167 0 : new_data->copy_percent = data->copy_percent;
168 0 : new_data->lv_tags = g_strdupv (data->lv_tags);
169 0 : return new_data;
170 : }
171 :
172 0 : void bd_lvm_lvdata_free (BDLVMLVdata *data) {
173 0 : if (data == NULL)
174 0 : return;
175 :
176 0 : g_free (data->lv_name);
177 0 : g_free (data->vg_name);
178 0 : g_free (data->uuid);
179 0 : g_free (data->attr);
180 0 : g_free (data->segtype);
181 0 : g_free (data->origin);
182 0 : g_free (data->pool_lv);
183 0 : g_free (data->data_lv);
184 0 : g_free (data->metadata_lv);
185 0 : g_free (data->roles);
186 0 : g_free (data->move_pv);
187 0 : g_strfreev (data->lv_tags);
188 0 : g_free (data);
189 : }
190 :
191 0 : BDLVMCacheStats* bd_lvm_cache_stats_copy (BDLVMCacheStats *data) {
192 0 : if (data == NULL)
193 0 : return NULL;
194 :
195 0 : BDLVMCacheStats *new = g_new0 (BDLVMCacheStats, 1);
196 :
197 0 : new->block_size = data->block_size;
198 0 : new->cache_size = data->cache_size;
199 0 : new->cache_used = data->cache_used;
200 0 : new->md_block_size = data->md_block_size;
201 0 : new->md_size = data->md_size;
202 0 : new->md_used = data->md_used;
203 0 : new->read_hits = data->read_hits;
204 0 : new->read_misses = data->read_misses;
205 0 : new->write_hits = data->write_hits;
206 0 : new->write_misses = data->write_misses;
207 0 : new->mode = data->mode;
208 :
209 0 : return new;
210 : }
211 :
212 0 : void bd_lvm_cache_stats_free (BDLVMCacheStats *data) {
213 0 : g_free (data);
214 0 : }
215 :
216 13 : static gboolean setup_dbus_connection (GError **error) {
217 13 : gchar *addr = NULL;
218 :
219 13 : addr = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, NULL, error);
220 13 : if (!addr) {
221 0 : g_prefix_error (error, "Failed to get system bus address: ");
222 0 : return FALSE;
223 : }
224 :
225 13 : bus = g_dbus_connection_new_for_address_sync (addr,
226 : G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT|
227 : G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
228 : NULL, NULL, error);
229 :
230 13 : g_free (addr);
231 :
232 13 : if (!bus) {
233 0 : g_prefix_error (error, "Failed to create a new connection for the system bus: ");
234 0 : return FALSE;
235 : }
236 :
237 13 : if (g_dbus_connection_is_closed (bus)) {
238 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_FAIL,
239 : "Connection is closed");
240 0 : return FALSE;
241 : }
242 :
243 13 : g_dbus_connection_set_exit_on_close (bus, FALSE);
244 :
245 13 : return TRUE;
246 : }
247 :
248 : static volatile guint avail_deps = 0;
249 : static volatile guint avail_dbus_deps = 0;
250 : static volatile guint avail_features = 0;
251 : static volatile guint avail_module_deps = 0;
252 : static GMutex deps_check_lock;
253 :
254 : #define DEPS_LVM 0
255 : #define DEPS_LVM_MASK (1 << DEPS_LVM)
256 : #define DEPS_LVMDEVICES 1
257 : #define DEPS_LVMDEVICES_MASK (1 << DEPS_LVMDEVICES)
258 : #define DEPS_LVMCONFIG 2
259 : #define DEPS_LVMCONFIG_MASK (1 << DEPS_LVMCONFIG)
260 : #define DEPS_LAST 3
261 :
262 : static const UtilDep deps[DEPS_LAST] = {
263 : {"lvm", LVM_MIN_VERSION, "version", "LVM version:\\s+([\\d\\.]+)"},
264 : {"lvmdevices", NULL, NULL, NULL},
265 : {"lvmconfig", "2.03.17", "--version", "LVM version:\\s+([\\d\\.]+)"},
266 : };
267 :
268 : #define DBUS_DEPS_LVMDBUSD 0
269 : #define DBUS_DEPS_LVMDBUSD_MASK (1 << DBUS_DEPS_LVMDBUSD)
270 : #define DBUS_DEPS_LVMDBUSD_WRITECACHE 1
271 : #define DBUS_DEPS_LVMDBUSD_WRITECACHE_MASK (1 << DBUS_DEPS_LVMDBUSD_WRITECACHE)
272 : #define DBUS_DEPS_LAST 2
273 :
274 : static const DBusDep dbus_deps[DBUS_DEPS_LAST] = {
275 : {LVM_BUS_NAME, LVM_OBJ_PREFIX, G_BUS_TYPE_SYSTEM, NULL, NULL, NULL, NULL},
276 : {LVM_BUS_NAME, LVM_OBJ_PREFIX, G_BUS_TYPE_SYSTEM, "1.1.0", "Version", MANAGER_INTF, MANAGER_OBJ},
277 : };
278 :
279 : #define FEATURES_VDO 0
280 : #define FEATURES_VDO_MASK (1 << FEATURES_VDO)
281 : #define FEATURES_WRITECACHE 0
282 : #define FEATURES_WRITECACHE_MASK (1 << FEATURES_WRITECACHE)
283 : #define FEATURES_LAST 2
284 :
285 : static const UtilFeatureDep features[FEATURES_LAST] = {
286 : {"lvm", "vdo", "segtypes", NULL},
287 : {"lvm", "writecache", "segtypes", NULL},
288 : };
289 :
290 : #define MODULE_DEPS_VDO 0
291 : #define MODULE_DEPS_VDO_MASK (1 << MODULE_DEPS_VDO)
292 : #define MODULE_DEPS_LAST 1
293 :
294 : static const gchar*const module_deps[MODULE_DEPS_LAST] = { "dm-vdo" };
295 :
296 : /**
297 : * bd_lvm_init:
298 : *
299 : * Initializes the plugin. **This function is called automatically by the
300 : * library's initialization functions.**
301 : *
302 : */
303 13 : gboolean bd_lvm_init (void) {
304 13 : GError *error = NULL;
305 :
306 : /* the check() call should create the DBus connection for us, but let's not
307 : completely rely on it */
308 13 : if (G_UNLIKELY (!bus) && !setup_dbus_connection (&error)) {
309 0 : bd_utils_log_format (BD_UTILS_LOG_CRIT, "Failed to setup DBus connection: %s", error->message);
310 0 : g_clear_error (&error);
311 0 : return FALSE;
312 : }
313 :
314 13 : dm_log_with_errno_init ((dm_log_with_errno_fn) redirect_dm_log);
315 : #ifdef DEBUG
316 : dm_log_init_verbose (LOG_DEBUG);
317 : #else
318 13 : dm_log_init_verbose (LOG_INFO);
319 : #endif
320 :
321 13 : return TRUE;
322 : }
323 :
324 : /**
325 : * bd_lvm_close:
326 : *
327 : * Cleans up after the plugin. **This function is called automatically by the
328 : * library's functions that unload it.**
329 : *
330 : */
331 13 : void bd_lvm_close (void) {
332 13 : GError *error = NULL;
333 :
334 : /* the check() call should create the DBus connection for us, but let's not
335 : completely rely on it */
336 13 : if (!g_dbus_connection_flush_sync (bus, NULL, &error)) {
337 0 : bd_utils_log_format (BD_UTILS_LOG_CRIT, "Failed to flush DBus connection: %s", error->message);
338 0 : g_clear_error (&error);
339 : }
340 13 : if (!g_dbus_connection_close_sync (bus, NULL, &error)) {
341 0 : bd_utils_log_format (BD_UTILS_LOG_CRIT, "Failed to close DBus connection: %s", error->message);
342 0 : g_clear_error (&error);
343 : }
344 :
345 13 : dm_log_with_errno_init (NULL);
346 13 : dm_log_init_verbose (0);
347 13 : }
348 :
349 : /**
350 : * bd_lvm_is_tech_avail:
351 : * @tech: the queried tech
352 : * @mode: a bit mask of queried modes of operation (#BDLVMTechMode) for @tech
353 : * @error: (out) (optional): place to store error (details about why the @tech-@mode combination is not available)
354 : *
355 : * Returns: whether the @tech-@mode combination is available -- supported by the
356 : * plugin implementation and having all the runtime dependencies available
357 : */
358 164 : gboolean bd_lvm_is_tech_avail (BDLVMTech tech, guint64 mode, GError **error) {
359 164 : switch (tech) {
360 1 : case BD_LVM_TECH_THIN_CALCS:
361 1 : if (mode & ~BD_LVM_TECH_MODE_QUERY) {
362 1 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_TECH_UNAVAIL,
363 : "Only 'query' supported for thin calculations");
364 1 : return FALSE;
365 : } else
366 0 : return TRUE;
367 0 : case BD_LVM_TECH_CALCS:
368 0 : if (mode & ~BD_LVM_TECH_MODE_QUERY) {
369 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_TECH_UNAVAIL,
370 : "Only 'query' supported for calculations");
371 0 : return FALSE;
372 : } else
373 0 : return TRUE;
374 0 : case BD_LVM_TECH_VDO:
375 0 : return check_dbus_deps (&avail_dbus_deps, DBUS_DEPS_LVMDBUSD_MASK, dbus_deps, DBUS_DEPS_LAST, &deps_check_lock, error) &&
376 0 : check_features (&avail_features, FEATURES_VDO_MASK, features, FEATURES_LAST, &deps_check_lock, error) &&
377 0 : check_module_deps (&avail_module_deps, MODULE_DEPS_VDO_MASK, module_deps, MODULE_DEPS_LAST, &deps_check_lock, error);
378 0 : case BD_LVM_TECH_WRITECACHE:
379 0 : return check_dbus_deps (&avail_dbus_deps, DBUS_DEPS_LVMDBUSD_MASK|DBUS_DEPS_LVMDBUSD_WRITECACHE_MASK, dbus_deps, DBUS_DEPS_LAST, &deps_check_lock, error) &&
380 0 : check_features (&avail_features, FEATURES_WRITECACHE_MASK, features, FEATURES_LAST, &deps_check_lock, error);
381 161 : case BD_LVM_TECH_DEVICES:
382 161 : return check_deps (&avail_deps, DEPS_LVMDEVICES_MASK, deps, DEPS_LAST, &deps_check_lock, error);
383 1 : case BD_LVM_TECH_CONFIG:
384 1 : return check_deps (&avail_deps, DEPS_LVMCONFIG_MASK, deps, DEPS_LAST, &deps_check_lock, error);
385 0 : case BD_LVM_TECH_VG_CFG_BACKUP_RESTORE:
386 0 : return check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error);
387 1 : default:
388 : /* everything is supported by this implementation of the plugin */
389 1 : return check_dbus_deps (&avail_dbus_deps, DBUS_DEPS_LVMDBUSD_MASK, dbus_deps, DBUS_DEPS_LAST, &deps_check_lock, error);
390 : }
391 : }
392 :
393 96 : static gchar** get_existing_objects (const gchar *obj_prefix, GError **error) {
394 96 : GVariant *intro_v = NULL;
395 96 : gchar *intro_data = NULL;
396 96 : GDBusNodeInfo *info = NULL;
397 96 : gchar **ret = NULL;
398 : GDBusNodeInfo **nodes;
399 96 : guint64 n_nodes = 0;
400 96 : guint64 i = 0;
401 :
402 96 : intro_v = g_dbus_connection_call_sync (bus, LVM_BUS_NAME, obj_prefix, DBUS_INTRO_IFACE,
403 : "Introspect", NULL, NULL, G_DBUS_CALL_FLAGS_NONE,
404 : -1, NULL, error);
405 96 : if (!intro_v)
406 : /* no introspection data, something went wrong (error must be set) */
407 0 : return NULL;
408 :
409 96 : g_variant_get (intro_v, "(s)", &intro_data);
410 96 : g_variant_unref (intro_v);
411 96 : info = g_dbus_node_info_new_for_xml (intro_data, error);
412 96 : g_free (intro_data);
413 :
414 150 : for (nodes = info->nodes; (*nodes); nodes++)
415 54 : n_nodes++;
416 :
417 96 : ret = g_new0 (gchar*, n_nodes + 1);
418 150 : for (nodes = info->nodes, i=0; (*nodes); nodes++, i++) {
419 54 : ret[i] = g_strdup_printf ("%s/%s", obj_prefix, ((*nodes)->path));
420 : }
421 96 : ret[i] = NULL;
422 :
423 96 : g_dbus_node_info_unref (info);
424 :
425 96 : return ret;
426 : }
427 :
428 :
429 : /**
430 : * get_object_path:
431 : * @obj_id: get object path for an LVM object (vgname/lvname)
432 : * @error: (out) (optional): place to store error (if any)
433 : *
434 : * Returns: (transfer full): object path
435 : */
436 683 : static gchar* get_object_path (const gchar *obj_id, GError **error) {
437 683 : GVariant *args = NULL;
438 683 : GVariant *ret = NULL;
439 683 : gchar *obj_path = NULL;
440 :
441 683 : args = g_variant_new ("(s)", obj_id);
442 : /* consumes (frees) the 'args' parameter */
443 683 : ret = g_dbus_connection_call_sync (bus, LVM_BUS_NAME, MANAGER_OBJ, MANAGER_INTF,
444 : "LookUpByLvmId", args, NULL, G_DBUS_CALL_FLAGS_NONE,
445 : -1, NULL, error);
446 683 : if (!ret)
447 : /* error is already set */
448 0 : return NULL;
449 :
450 683 : g_variant_get (ret, "(o)", &obj_path);
451 683 : g_variant_unref (ret);
452 :
453 683 : if (g_strcmp0 (obj_path, "/") == 0) {
454 : /* not a valid path (at least for us) */
455 110 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOEXIST,
456 : "The object with LVM ID '%s' doesn't exist", obj_id);
457 110 : g_free (obj_path);
458 110 : return NULL;
459 : }
460 :
461 573 : return obj_path;
462 : }
463 :
464 : /**
465 : * get_object_property:
466 : * @obj_path: lvmdbusd object path
467 : * @iface: interface on @obj_path object
468 : * @property: property to get from @obj_path and @iface
469 : * @error: (out) (optional): place to store error (if any)
470 : *
471 : * Returns: (transfer full): object path
472 : */
473 394 : static GVariant* get_object_property (const gchar *obj_path, const gchar *iface, const gchar *property, GError **error) {
474 394 : GVariant *args = NULL;
475 394 : GVariant *ret = NULL;
476 394 : GVariant *real_ret = NULL;
477 :
478 394 : args = g_variant_new ("(ss)", iface, property);
479 :
480 : /* consumes (frees) the 'args' parameter */
481 394 : ret = g_dbus_connection_call_sync (bus, LVM_BUS_NAME, obj_path, DBUS_PROPS_IFACE,
482 : "Get", args, NULL, G_DBUS_CALL_FLAGS_NONE,
483 : -1, NULL, error);
484 394 : if (!ret) {
485 0 : g_prefix_error (error, "Failed to get %s property of the %s object: ", property, obj_path);
486 0 : return NULL;
487 : }
488 :
489 394 : g_variant_get (ret, "(v)", &real_ret);
490 394 : g_variant_unref (ret);
491 :
492 394 : return real_ret;
493 : }
494 :
495 : /**
496 : * get_lvm_object_property:
497 : * @obj_id: LVM object to get the property for (vgname/lvname)
498 : * @iface: interface where @property is defined
499 : * @property: property to get from @obj_id and @iface
500 : * @error: (out) (optional): place to store error (if any)
501 : *
502 : * Returns: (transfer full): property variant
503 : */
504 76 : static GVariant* get_lvm_object_property (const gchar *obj_id, const gchar *iface, const gchar *property, GError **error) {
505 76 : gchar *obj_path = NULL;
506 76 : GVariant *ret = NULL;
507 :
508 76 : obj_path = get_object_path (obj_id, error);
509 76 : if (!obj_path)
510 : /* error is already set */
511 0 : return NULL;
512 : else {
513 76 : ret = get_object_property (obj_path, iface, property, error);
514 76 : g_free (obj_path);
515 76 : return ret;
516 : }
517 : }
518 :
519 12 : static gboolean unbox_params_and_add (GVariant *params, GVariantBuilder *builder) {
520 : GVariantIter iter;
521 12 : GVariant *param = NULL;
522 12 : gboolean ret = FALSE;
523 :
524 12 : if (g_variant_is_of_type (params, G_VARIANT_TYPE_DICTIONARY)) {
525 12 : g_variant_iter_init (&iter, params);
526 34 : while ((param = g_variant_iter_next_value (&iter))) {
527 22 : g_variant_builder_add_value (builder, param);
528 22 : ret = TRUE;
529 : }
530 12 : return ret;
531 : }
532 :
533 0 : if (g_variant_is_of_type (params, G_VARIANT_TYPE_VARIANT)) {
534 0 : param = g_variant_get_variant (params);
535 0 : return unbox_params_and_add (param, builder);
536 : }
537 :
538 0 : if (g_variant_is_container (params)) {
539 0 : g_variant_iter_init (&iter, params);
540 0 : while ((param = g_variant_iter_next_value (&iter)))
541 0 : ret = unbox_params_and_add (param, builder);
542 0 : return ret;
543 : }
544 :
545 0 : return FALSE;
546 : }
547 :
548 : /**
549 : * call_lvm_method
550 : * @obj: lvmdbusd object path
551 : * @intf: interface to call @method on
552 : * @method: method to call
553 : * @params: parameters for @method
554 : * @extra_params: extra parameters for @method
555 : * @extra_args: extra command line argument to be passed to the LVM command
556 : * @task_id: (out): task ID to watch progress of the operation
557 : * @progress_id: (out): progress ID to watch progress of the operation
558 : * @lock_config: whether to lock %global_config_lock or not (if %FALSE is given, caller is responsible
559 : * for holding the lock for this call)
560 : * @error: (out) (optional): place to store error (if any)
561 : *
562 : * Returns: (transfer full): return value of @method (variant)
563 : */
564 441 : static GVariant* call_lvm_method (const gchar *obj, const gchar *intf, const gchar *method, GVariant *params, GVariant *extra_params, const BDExtraArg **extra_args, guint64 *task_id, guint64 *progress_id, gboolean lock_config, GError **error) {
565 441 : GVariant *config = NULL;
566 441 : GVariant *devices = NULL;
567 441 : GVariant *param = NULL;
568 : GVariantIter iter;
569 : GVariantBuilder builder;
570 : GVariantBuilder extra_builder;
571 441 : GVariant *config_extra_params = NULL;
572 441 : GVariant *tmo = NULL;
573 441 : GVariant *all_params = NULL;
574 441 : GVariant *ret = NULL;
575 441 : gchar *params_str = NULL;
576 441 : gchar *log_msg = NULL;
577 441 : gchar *prog_msg = NULL;
578 441 : const BDExtraArg **extra_p = NULL;
579 441 : gboolean added_extra = FALSE;
580 :
581 441 : if (!check_dbus_deps (&avail_dbus_deps, DBUS_DEPS_LVMDBUSD_MASK, dbus_deps, DBUS_DEPS_LAST, &deps_check_lock, error))
582 0 : return NULL;
583 :
584 : /* don't allow global config string changes during the run */
585 441 : if (lock_config)
586 434 : g_mutex_lock (&global_config_lock);
587 :
588 441 : if (global_config_str || global_devices_str || extra_params || extra_args) {
589 213 : if (global_config_str || global_devices_str || extra_args) {
590 : /* add the global config to the extra_params */
591 17 : g_variant_builder_init (&extra_builder, G_VARIANT_TYPE_DICTIONARY);
592 :
593 17 : if (extra_params)
594 12 : added_extra = unbox_params_and_add (extra_params, &extra_builder);
595 :
596 17 : if (extra_args) {
597 4 : for (extra_p=extra_args; *extra_p; extra_p++) {
598 4 : g_variant_builder_add (&extra_builder, "{sv}",
599 2 : (*extra_p)->opt ? (*extra_p)->opt : "",
600 : g_variant_new ("s",
601 2 : (*extra_p)->val ? (*extra_p)->val : ""));
602 2 : added_extra = TRUE;
603 : }
604 : }
605 17 : if (global_config_str) {
606 14 : config = g_variant_new ("s", global_config_str);
607 14 : g_variant_builder_add (&extra_builder, "{sv}", "--config", config);
608 14 : added_extra = TRUE;
609 : }
610 17 : if (global_devices_str) {
611 1 : devices = g_variant_new ("s", global_devices_str);
612 1 : g_variant_builder_add (&extra_builder, "{sv}", "--devices", devices);
613 1 : added_extra = TRUE;
614 : }
615 :
616 17 : if (added_extra)
617 17 : config_extra_params = g_variant_builder_end (&extra_builder);
618 17 : g_variant_builder_clear (&extra_builder);
619 : } else
620 : /* just use the extra_params */
621 196 : config_extra_params = extra_params;
622 : }
623 :
624 441 : if (!config_extra_params)
625 : /* create an empty dictionary with the extra arguments */
626 228 : config_extra_params = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
627 :
628 : /* create new GVariant holding the given parameters with the global
629 : config and extra_params merged together appended */
630 441 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
631 :
632 441 : if (params) {
633 : /* add parameters */
634 269 : g_variant_iter_init (&iter, params);
635 753 : while ((param = g_variant_iter_next_value (&iter))) {
636 484 : g_variant_builder_add_value (&builder, param);
637 484 : g_variant_unref (param);
638 : }
639 : }
640 :
641 : /* add the timeout spec (in seconds) */
642 441 : tmo = g_variant_new ("i", 1);
643 441 : g_variant_builder_add_value (&builder, tmo);
644 :
645 : /* add extra parameters including config */
646 441 : g_variant_builder_add_value (&builder, config_extra_params);
647 :
648 441 : all_params = g_variant_builder_end (&builder);
649 441 : g_variant_builder_clear (&builder);
650 :
651 441 : params_str = g_variant_print (all_params, FALSE);
652 :
653 441 : *task_id = bd_utils_get_next_task_id ();
654 441 : log_msg = g_strdup_printf ("Calling the '%s.%s' method on the '%s' object with the following parameters: '%s'",
655 : intf, method, obj, params_str);
656 441 : bd_utils_log_task_status (*task_id, log_msg);
657 441 : g_free (log_msg);
658 :
659 : /* now do the call with all the parameters */
660 441 : ret = g_dbus_connection_call_sync (bus, LVM_BUS_NAME, obj, intf, method, all_params,
661 : NULL, G_DBUS_CALL_FLAGS_NONE, METHOD_CALL_TIMEOUT, NULL, error);
662 :
663 441 : if (lock_config)
664 434 : g_mutex_unlock (&global_config_lock);
665 441 : prog_msg = g_strdup_printf ("Started the '%s.%s' method on the '%s' object with the following parameters: '%s'",
666 : intf, method, obj, params_str);
667 441 : g_free (params_str);
668 441 : *progress_id = bd_utils_report_started (prog_msg);
669 441 : g_free (prog_msg);
670 :
671 441 : if (!ret) {
672 5 : g_prefix_error (error, "Failed to call the '%s' method on the '%s' object: ", method, obj);
673 5 : return NULL;
674 : }
675 :
676 436 : return ret;
677 : }
678 :
679 : /**
680 : * call_lvm_method_sync
681 : * @obj: lvmdbusd object path
682 : * @intf: interface to call @method on
683 : * @method: method to call
684 : * @params: parameters for @method
685 : * @extra_params: extra parameters for @method
686 : * @extra_args: extra command line argument to be passed to the LVM command
687 : * @lock_config: whether to lock %global_config_lock or not (if %FALSE is given, caller is responsible
688 : * for holding the lock for this call)
689 : * @error: (out) (optional): place to store error (if any)
690 : *
691 : * Returns: whether calling the method was successful or not
692 : */
693 441 : static gboolean call_lvm_method_sync (const gchar *obj, const gchar *intf, const gchar *method, GVariant *params, GVariant *extra_params, const BDExtraArg **extra_args, gboolean lock_config, GError **error) {
694 441 : GVariant *ret = NULL;
695 441 : gchar *obj_path = NULL;
696 441 : g_autofree gchar *task_path = NULL;
697 441 : guint64 log_task_id = 0;
698 441 : guint64 prog_id = 0;
699 441 : gdouble progress = 0.0;
700 441 : gchar *log_msg = NULL;
701 441 : gboolean completed = FALSE;
702 441 : gint64 error_code = 0;
703 441 : gchar *error_msg = NULL;
704 441 : GError *l_error = NULL;
705 :
706 441 : ret = call_lvm_method (obj, intf, method, params, extra_params, extra_args, &log_task_id, &prog_id, lock_config, &l_error);
707 441 : bd_utils_log_task_status (log_task_id, "Done.");
708 441 : if (!ret) {
709 5 : if (l_error) {
710 5 : log_msg = g_strdup_printf ("Got error: %s", l_error->message);
711 5 : bd_utils_log_task_status (log_task_id, log_msg);
712 5 : bd_utils_report_finished (prog_id, log_msg);
713 5 : g_free (log_msg);
714 5 : g_propagate_error (error, l_error);
715 : } else {
716 0 : bd_utils_log_task_status (log_task_id, "Got unknown error");
717 0 : bd_utils_report_finished (prog_id, "Got unknown error");
718 : }
719 5 : return FALSE;
720 : }
721 436 : if (g_variant_check_format_string (ret, "((oo))", TRUE)) {
722 211 : g_variant_get (ret, "((oo))", &obj_path, &task_path);
723 211 : if (g_strcmp0 (obj_path, "/") != 0) {
724 209 : log_msg = g_strdup_printf ("Got result: %s", obj_path);
725 209 : bd_utils_log_task_status (log_task_id, log_msg);
726 209 : g_free (log_msg);
727 : /* got a valid result, just return */
728 209 : g_variant_unref (ret);
729 209 : g_free (obj_path);
730 209 : bd_utils_report_finished (prog_id, "Completed");
731 209 : return TRUE;
732 : } else {
733 2 : g_variant_unref (ret);
734 2 : g_free (obj_path);
735 2 : if (g_strcmp0 (task_path, "/") == 0) {
736 0 : log_msg = g_strdup_printf ("Task finished without result and without job started");
737 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_FAIL,
738 : "Running '%s' method on the '%s' object failed: %s",
739 : method, obj, log_msg);
740 0 : bd_utils_log_task_status (log_task_id, log_msg);
741 0 : bd_utils_report_finished (prog_id, log_msg);
742 0 : g_free (log_msg);
743 0 : return FALSE;
744 : }
745 : }
746 225 : } else if (g_variant_check_format_string (ret, "(o)", TRUE)) {
747 225 : g_variant_get (ret, "(o)", &task_path);
748 225 : if (g_strcmp0 (task_path, "/") != 0) {
749 2 : g_variant_unref (ret);
750 : } else {
751 223 : bd_utils_log_task_status (log_task_id, "No result, no job started");
752 223 : bd_utils_report_finished (prog_id, "Completed");
753 223 : g_variant_unref (ret);
754 223 : return TRUE;
755 : }
756 : } else {
757 0 : g_variant_unref (ret);
758 0 : bd_utils_log_task_status (log_task_id, "Failed to parse the returned value!");
759 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_PARSE,
760 : "Failed to parse the returned value!");
761 0 : bd_utils_report_finished (prog_id, "Failed to parse the returned value!");
762 0 : return FALSE;
763 : }
764 :
765 4 : log_msg = g_strdup_printf ("Waiting for job '%s' to finish", task_path);
766 4 : bd_utils_log_task_status (log_task_id, log_msg);
767 4 : g_free (log_msg);
768 :
769 4 : ret = NULL;
770 8 : while (!completed && !l_error) {
771 4 : g_usleep (PROGRESS_WAIT);
772 4 : ret = get_object_property (task_path, JOB_INTF, "Complete", &l_error);
773 4 : if (ret) {
774 4 : g_variant_get (ret, "b", &completed);
775 4 : g_variant_unref (ret);
776 4 : ret = NULL;
777 : }
778 4 : if (!completed && !l_error) {
779 : /* let's report progress and wait longer */
780 0 : ret = get_object_property (task_path, JOB_INTF, "Percent", &l_error);
781 0 : if (ret) {
782 0 : g_variant_get (ret, "d", &progress);
783 0 : bd_utils_report_progress (prog_id, (gint) progress, NULL);
784 0 : g_variant_unref (ret);
785 0 : ret = NULL;
786 : } else {
787 0 : bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Got error when getting progress: %s", l_error->message);
788 0 : g_clear_error (&l_error);
789 : }
790 0 : log_msg = g_strdup_printf ("Still waiting for job '%s' to finish", task_path);
791 0 : bd_utils_log_task_status (log_task_id, log_msg);
792 0 : g_free (log_msg);
793 : }
794 :
795 : }
796 4 : log_msg = g_strdup_printf ("Job '%s' finished", task_path);
797 4 : bd_utils_log_task_status (log_task_id, log_msg);
798 4 : g_free (log_msg);
799 :
800 4 : obj_path = NULL;
801 4 : if (!l_error) {
802 4 : ret = get_object_property (task_path, JOB_INTF, "Result", &l_error);
803 4 : if (!ret) {
804 0 : g_prefix_error (&l_error, "Getting result after waiting for '%s' method of the '%s' object failed: ",
805 : method, obj);
806 0 : bd_utils_report_finished (prog_id, l_error->message);
807 0 : g_propagate_error (error, l_error);
808 0 : return FALSE;
809 : } else {
810 4 : g_variant_get (ret, "o", &obj_path);
811 4 : g_variant_unref (ret);
812 4 : if (g_strcmp0 (obj_path, "/") != 0) {
813 2 : log_msg = g_strdup_printf ("Got result: %s", obj_path);
814 2 : bd_utils_log_task_status (log_task_id, log_msg);
815 2 : g_free (log_msg);
816 : } else {
817 2 : ret = get_object_property (task_path, JOB_INTF, "GetError", &l_error);
818 2 : g_variant_get (ret, "(is)", &error_code, &error_msg);
819 2 : if (error_code != 0) {
820 0 : if (error_msg) {
821 0 : log_msg = g_strdup_printf ("Got error: %s", error_msg);
822 0 : bd_utils_log_task_status (log_task_id, log_msg);
823 0 : bd_utils_report_finished (prog_id, log_msg);
824 0 : g_set_error (&l_error, BD_LVM_ERROR, BD_LVM_ERROR_FAIL,
825 : "Running '%s' method on the '%s' object failed: %s",
826 : method, obj, error_msg);
827 0 : g_free (log_msg);
828 0 : g_free (error_msg);
829 : } else {
830 0 : bd_utils_log_task_status (log_task_id, "Got unknown error");
831 0 : bd_utils_report_finished (prog_id, "Got unknown error");
832 0 : g_set_error (&l_error, BD_LVM_ERROR, BD_LVM_ERROR_FAIL,
833 : "Got unknown error when running '%s' method on the '%s' object.",
834 : method, obj);
835 : }
836 0 : g_propagate_error (error, l_error);
837 0 : return FALSE;
838 : } else
839 2 : bd_utils_log_task_status (log_task_id, "No result");
840 : }
841 4 : bd_utils_report_finished (prog_id, "Completed");
842 4 : g_free (obj_path);
843 :
844 : /* remove the job object and clean after ourselves */
845 4 : ret = g_dbus_connection_call_sync (bus, LVM_BUS_NAME, task_path, JOB_INTF, "Remove", NULL,
846 : NULL, G_DBUS_CALL_FLAGS_NONE, METHOD_CALL_TIMEOUT, NULL, NULL);
847 4 : if (ret)
848 4 : g_variant_unref (ret);
849 :
850 4 : return TRUE;
851 : }
852 : } else {
853 : /* some real error */
854 0 : g_prefix_error (&l_error, "Waiting for '%s' method of the '%s' object to finish failed: ",
855 : method, obj);
856 0 : g_propagate_error (error, l_error);
857 0 : bd_utils_report_finished (prog_id, "Completed");
858 0 : return FALSE;
859 : }
860 : }
861 :
862 399 : static gboolean call_lvm_obj_method_sync (const gchar *obj_id, const gchar *intf, const gchar *method, GVariant *params, GVariant *extra_params, const BDExtraArg **extra_args, gboolean lock_config, GError **error) {
863 798 : g_autofree gchar *obj_path = get_object_path (obj_id, error);
864 399 : if (!obj_path)
865 105 : return FALSE;
866 :
867 294 : return call_lvm_method_sync (obj_path, intf, method, params, extra_params, extra_args, lock_config, error);
868 : }
869 :
870 93 : static gboolean call_lv_method_sync (const gchar *vg_name, const gchar *lv_name, const gchar *method, GVariant *params, GVariant *extra_params, const BDExtraArg **extra_args, gboolean lock_config, GError **error) {
871 186 : g_autofree gchar *obj_id = g_strdup_printf ("%s/%s", vg_name, lv_name);
872 :
873 93 : return call_lvm_obj_method_sync (obj_id, LV_INTF, method, params, extra_params, extra_args, lock_config, error);
874 : }
875 :
876 2 : static gboolean call_thpool_method_sync (const gchar *vg_name, const gchar *pool_name, const gchar *method, GVariant *params, GVariant *extra_params, const BDExtraArg **extra_args, gboolean lock_config, GError **error) {
877 4 : g_autofree gchar *obj_id = g_strdup_printf ("%s/%s", vg_name, pool_name);
878 :
879 2 : return call_lvm_obj_method_sync (obj_id, THPOOL_INTF, method, params, extra_params, extra_args, lock_config, error);
880 : }
881 :
882 4 : static gboolean call_vdopool_method_sync (const gchar *vg_name, const gchar *pool_name, const gchar *method, GVariant *params, GVariant *extra_params, const BDExtraArg **extra_args, gboolean lock_config, GError **error) {
883 8 : g_autofree gchar *obj_id = g_strdup_printf ("%s/%s", vg_name, pool_name);
884 :
885 4 : return call_lvm_obj_method_sync (obj_id, VDO_POOL_INTF, method, params, extra_params, extra_args, lock_config, error);
886 : }
887 :
888 71 : static GVariant* get_lv_property (const gchar *vg_name, const gchar *lv_name, const gchar *property, GError **error) {
889 71 : gchar *lv_spec = NULL;
890 71 : GVariant *ret = NULL;
891 :
892 71 : lv_spec = g_strdup_printf ("%s/%s", vg_name, lv_name);
893 :
894 71 : ret = get_lvm_object_property (lv_spec, LV_CMN_INTF, property, error);
895 71 : g_free (lv_spec);
896 :
897 71 : return ret;
898 : }
899 :
900 137 : static GVariant* get_object_properties (const gchar *obj_path, const gchar *iface, GError **error) {
901 137 : GVariant *args = NULL;
902 137 : GVariant *ret = NULL;
903 137 : GVariant *real_ret = NULL;
904 :
905 137 : args = g_variant_new ("(s)", iface);
906 :
907 : /* consumes (frees) the 'args' parameter */
908 137 : ret = g_dbus_connection_call_sync (bus, LVM_BUS_NAME, obj_path, DBUS_PROPS_IFACE,
909 : "GetAll", args, NULL, G_DBUS_CALL_FLAGS_NONE,
910 : -1, NULL, error);
911 137 : if (!ret) {
912 0 : g_prefix_error (error, "Failed to get properties of the %s object: ", obj_path);
913 0 : return NULL;
914 : }
915 :
916 137 : real_ret = g_variant_get_child_value (ret, 0);
917 137 : g_variant_unref (ret);
918 :
919 137 : return real_ret;
920 : }
921 :
922 70 : static GVariant* get_lvm_object_properties (const gchar *obj_id, const gchar *iface, GError **error) {
923 70 : GVariant *args = NULL;
924 70 : GVariant *ret = NULL;
925 70 : gchar *obj_path = NULL;
926 :
927 70 : if (!obj_id || g_strcmp0 (obj_id, "") == 0) {
928 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOEXIST,
929 : "Invalid LVM ID specified");
930 0 : return NULL;
931 : }
932 :
933 70 : args = g_variant_new ("(s)", obj_id);
934 : /* consumes (frees) the 'args' parameter */
935 70 : ret = g_dbus_connection_call_sync (bus, LVM_BUS_NAME, MANAGER_OBJ, MANAGER_INTF,
936 : "LookUpByLvmId", args, NULL, G_DBUS_CALL_FLAGS_NONE,
937 : -1, NULL, error);
938 70 : g_variant_get (ret, "(o)", &obj_path);
939 70 : g_variant_unref (ret);
940 :
941 70 : if (g_strcmp0 (obj_path, "/") == 0) {
942 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOEXIST,
943 : "The object with LVM ID '%s' doesn't exist", obj_id);
944 0 : g_free (obj_path);
945 0 : return NULL;
946 : }
947 :
948 70 : ret = get_object_properties (obj_path, iface, error);
949 70 : g_free (obj_path);
950 70 : return ret;
951 : }
952 :
953 :
954 14 : static GVariant* get_pv_properties (const gchar *pv_name, GError **error) {
955 14 : gchar *obj_id = NULL;
956 14 : GVariant *ret = NULL;
957 :
958 14 : if (!g_str_has_prefix (pv_name, "/dev/")) {
959 0 : obj_id = g_strdup_printf ("/dev/%s", pv_name);
960 0 : ret = get_lvm_object_properties (obj_id, PV_INTF, error);
961 0 : g_free (obj_id);
962 : } else
963 14 : ret = get_lvm_object_properties (pv_name, PV_INTF, error);
964 :
965 14 : return ret;
966 : }
967 :
968 6 : static GVariant* get_vg_properties (const gchar *vg_name, GError **error) {
969 6 : GVariant *ret = NULL;
970 :
971 6 : ret = get_lvm_object_properties (vg_name, VG_INTF, error);
972 :
973 6 : return ret;
974 : }
975 :
976 41 : static GVariant* get_lv_properties (const gchar *vg_name, const gchar *lv_name, GError **error) {
977 41 : gchar *lvm_spec = NULL;
978 41 : GVariant *ret = NULL;
979 :
980 41 : lvm_spec = g_strdup_printf ("%s/%s", vg_name, lv_name);
981 :
982 41 : ret = get_lvm_object_properties (lvm_spec, LV_CMN_INTF, error);
983 41 : g_free (lvm_spec);
984 :
985 41 : return ret;
986 : }
987 :
988 9 : static GVariant* get_vdo_properties (const gchar *vg_name, const gchar *pool_name, GError **error) {
989 9 : gchar *lvm_spec = NULL;
990 9 : GVariant *ret = NULL;
991 :
992 9 : lvm_spec = g_strdup_printf ("%s/%s", vg_name, pool_name);
993 :
994 9 : ret = get_lvm_object_properties (lvm_spec, VDO_POOL_INTF, error);
995 9 : g_free (lvm_spec);
996 :
997 9 : return ret;
998 : }
999 :
1000 20 : static BDLVMPVdata* get_pv_data_from_props (GVariant *props, GError **error G_GNUC_UNUSED) {
1001 20 : BDLVMPVdata *data = g_new0 (BDLVMPVdata, 1);
1002 : GVariantDict dict;
1003 20 : gchar *path = NULL;
1004 20 : GVariant *vg_props = NULL;
1005 20 : GVariant *value = NULL;
1006 20 : gsize n_children = 0;
1007 20 : gsize i = 0;
1008 20 : gchar **tags = NULL;
1009 20 : GError *l_error = NULL;
1010 :
1011 20 : g_variant_dict_init (&dict, props);
1012 :
1013 20 : g_variant_dict_lookup (&dict, "Name", "s", &(data->pv_name));
1014 20 : g_variant_dict_lookup (&dict, "Uuid", "s", &(data->pv_uuid));
1015 20 : g_variant_dict_lookup (&dict, "FreeBytes", "t", &(data->pv_free));
1016 20 : g_variant_dict_lookup (&dict, "SizeBytes", "t", &(data->pv_size));
1017 20 : g_variant_dict_lookup (&dict, "PeStart", "t", &(data->pe_start));
1018 20 : g_variant_dict_lookup (&dict, "Missing", "b", &(data->missing));
1019 :
1020 20 : value = g_variant_dict_lookup_value (&dict, "Tags", (GVariantType*) "as");
1021 20 : if (value) {
1022 20 : n_children = g_variant_n_children (value);
1023 20 : tags = g_new0 (gchar*, n_children + 1);
1024 30 : for (i=0; i < n_children; i++) {
1025 10 : g_variant_get_child (value, i, "s", tags+i);
1026 : }
1027 20 : data->pv_tags = tags;
1028 20 : g_variant_unref (value);
1029 : }
1030 :
1031 : /* returns an object path for the VG */
1032 20 : g_variant_dict_lookup (&dict, "Vg", "&o", &path);
1033 20 : if (g_strcmp0 (path, "/") == 0) {
1034 : /* no VG, the PV is not part of any VG */
1035 7 : g_variant_dict_clear (&dict);
1036 7 : return data;
1037 : }
1038 :
1039 13 : vg_props = get_object_properties (path, VG_INTF, &l_error);
1040 13 : g_variant_dict_clear (&dict);
1041 13 : if (!vg_props) {
1042 0 : if (l_error) {
1043 0 : bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Failed to get VG properties for PV %s: %s",
1044 0 : data->pv_name, l_error->message);
1045 0 : g_clear_error (&l_error);
1046 : }
1047 0 : return data;
1048 : }
1049 :
1050 13 : g_variant_dict_init (&dict, vg_props);
1051 13 : g_variant_dict_lookup (&dict, "Name", "s", &(data->vg_name));
1052 13 : g_variant_dict_lookup (&dict, "Uuid", "s", &(data->vg_uuid));
1053 13 : g_variant_dict_lookup (&dict, "SizeBytes", "t", &(data->vg_size));
1054 13 : g_variant_dict_lookup (&dict, "FreeBytes", "t", &(data->vg_free));
1055 13 : g_variant_dict_lookup (&dict, "ExtentSizeBytes", "t", &(data->vg_extent_size));
1056 13 : g_variant_dict_lookup (&dict, "ExtentCount", "t", &(data->vg_extent_count));
1057 13 : g_variant_dict_lookup (&dict, "FreeCount", "t", &(data->vg_free_count));
1058 13 : g_variant_dict_lookup (&dict, "PvCount", "t", &(data->vg_pv_count));
1059 :
1060 13 : g_variant_dict_clear (&dict);
1061 13 : g_variant_unref (vg_props);
1062 :
1063 13 : return data;
1064 : }
1065 :
1066 7 : static BDLVMVGdata* get_vg_data_from_props (GVariant *props, GError **error G_GNUC_UNUSED) {
1067 7 : BDLVMVGdata *data = g_new0 (BDLVMVGdata, 1);
1068 : GVariantDict dict;
1069 7 : GVariant *value = NULL;
1070 7 : gsize n_children = 0;
1071 7 : gsize i = 0;
1072 7 : gchar **tags = NULL;
1073 :
1074 7 : g_variant_dict_init (&dict, props);
1075 :
1076 7 : g_variant_dict_lookup (&dict, "Name", "s", &(data->name));
1077 7 : g_variant_dict_lookup (&dict, "Uuid", "s", &(data->uuid));
1078 :
1079 7 : g_variant_dict_lookup (&dict, "SizeBytes", "t", &(data->size));
1080 7 : g_variant_dict_lookup (&dict, "FreeBytes", "t", &(data->free));
1081 7 : g_variant_dict_lookup (&dict, "ExtentSizeBytes", "t", &(data->extent_size));
1082 7 : g_variant_dict_lookup (&dict, "ExtentCount", "t", &(data->extent_count));
1083 7 : g_variant_dict_lookup (&dict, "FreeCount", "t", &(data->free_count));
1084 7 : g_variant_dict_lookup (&dict, "PvCount", "t", &(data->pv_count));
1085 7 : g_variant_dict_lookup (&dict, "Exportable", "b", &(data->exported));
1086 :
1087 7 : value = g_variant_dict_lookup_value (&dict, "Tags", (GVariantType*) "as");
1088 7 : if (value) {
1089 7 : n_children = g_variant_n_children (value);
1090 7 : tags = g_new0 (gchar*, n_children + 1);
1091 13 : for (i=0; i < n_children; i++) {
1092 6 : g_variant_get_child (value, i, "s", tags+i);
1093 : }
1094 7 : data->vg_tags = tags;
1095 7 : g_variant_unref (value);
1096 : }
1097 :
1098 7 : g_variant_dict_clear (&dict);
1099 :
1100 7 : return data;
1101 : }
1102 :
1103 16 : static gchar* _lvm_data_lv_name (const gchar *vg_name, const gchar *lv_name, GError **error) {
1104 16 : GVariant *prop = NULL;
1105 16 : gchar *obj_id = NULL;
1106 16 : gchar *obj_path = NULL;
1107 16 : gchar *ret = NULL;
1108 16 : gchar *segtype = NULL;
1109 :
1110 16 : obj_id = g_strdup_printf ("%s/%s", vg_name, lv_name);
1111 16 : obj_path = get_object_path (obj_id, error);
1112 16 : g_free (obj_id);
1113 16 : if (!obj_path)
1114 0 : return NULL;
1115 :
1116 16 : prop = get_lv_property (vg_name, lv_name, "SegType", error);
1117 16 : if (!prop)
1118 0 : return NULL;
1119 16 : g_variant_get_child (prop, 0, "s", &segtype);
1120 16 : g_variant_unref (prop);
1121 :
1122 16 : if (g_strcmp0 (segtype, "thin-pool") == 0)
1123 8 : prop = get_object_property (obj_path, THPOOL_INTF, "DataLv", NULL);
1124 8 : else if (g_strcmp0 (segtype, "cache-pool") == 0)
1125 2 : prop = get_object_property (obj_path, CACHE_POOL_INTF, "DataLv", NULL);
1126 6 : else if (g_strcmp0 (segtype, "vdo-pool") == 0)
1127 6 : prop = get_object_property (obj_path, VDO_POOL_INTF, "DataLv", NULL);
1128 :
1129 16 : g_free (segtype);
1130 16 : g_free (obj_path);
1131 16 : if (!prop)
1132 0 : return NULL;
1133 16 : g_variant_get (prop, "o", &obj_path);
1134 16 : g_variant_unref (prop);
1135 :
1136 16 : if (g_strcmp0 (obj_path, "/") == 0) {
1137 : /* no origin LV */
1138 0 : g_free (obj_path);
1139 0 : return NULL;
1140 : }
1141 16 : prop = get_object_property (obj_path, LV_CMN_INTF, "Name", error);
1142 16 : if (!prop) {
1143 0 : g_free (obj_path);
1144 0 : return NULL;
1145 : }
1146 :
1147 16 : g_variant_get (prop, "s", &ret);
1148 16 : g_variant_unref (prop);
1149 :
1150 16 : return g_strstrip (g_strdelimit (ret, "[]", ' '));
1151 : }
1152 :
1153 10 : static gchar* _lvm_metadata_lv_name (const gchar *vg_name, const gchar *lv_name, GError **error) {
1154 10 : GVariant *prop = NULL;
1155 10 : gchar *obj_id = NULL;
1156 10 : gchar *obj_path = NULL;
1157 10 : gchar *ret = NULL;
1158 :
1159 10 : obj_id = g_strdup_printf ("%s/%s", vg_name, lv_name);
1160 10 : obj_path = get_object_path (obj_id, error);
1161 10 : g_free (obj_id);
1162 10 : if (!obj_path)
1163 0 : return NULL;
1164 :
1165 10 : prop = get_object_property (obj_path, THPOOL_INTF, "MetaDataLv", NULL);
1166 10 : if (!prop)
1167 0 : prop = get_object_property (obj_path, CACHE_POOL_INTF, "MetaDataLv", NULL);
1168 10 : g_free (obj_path);
1169 10 : if (!prop)
1170 0 : return NULL;
1171 10 : g_variant_get (prop, "o", &obj_path);
1172 10 : g_variant_unref (prop);
1173 :
1174 10 : if (g_strcmp0 (obj_path, "/") == 0) {
1175 : /* no origin LV */
1176 0 : g_free (obj_path);
1177 0 : return NULL;
1178 : }
1179 10 : prop = get_object_property (obj_path, LV_CMN_INTF, "Name", error);
1180 10 : if (!prop) {
1181 0 : g_free (obj_path);
1182 0 : return NULL;
1183 : }
1184 :
1185 10 : g_variant_get (prop, "s", &ret);
1186 10 : g_variant_unref (prop);
1187 :
1188 10 : return g_strstrip (g_strdelimit (ret, "[]", ' '));
1189 : }
1190 :
1191 24 : static BDLVMSEGdata** _lvm_segs (const gchar *vg_name, const gchar *lv_name, GError **error) {
1192 24 : GVariant *prop = NULL;
1193 : BDLVMSEGdata **segs;
1194 : gsize n_segs;
1195 : GVariantIter iter, iter2;
1196 : GVariant *pv_segs, *pv_name_prop;
1197 : const gchar *pv;
1198 : gchar *pv_name;
1199 : guint64 pv_first_pe, pv_last_pe;
1200 : int i;
1201 :
1202 24 : prop = get_lv_property (vg_name, lv_name, "Devices", error);
1203 24 : if (!prop)
1204 0 : return NULL;
1205 :
1206 : /* Count number of segments */
1207 24 : n_segs = 0;
1208 24 : g_variant_iter_init (&iter, prop);
1209 40 : while (g_variant_iter_next (&iter, "(&o@a(tts))", NULL, &pv_segs)) {
1210 16 : n_segs += g_variant_n_children (pv_segs);
1211 16 : g_variant_unref (pv_segs);
1212 : }
1213 :
1214 24 : if (n_segs == 0) {
1215 8 : g_variant_unref (prop);
1216 8 : return NULL;
1217 : }
1218 :
1219 : /* Build segments */
1220 16 : segs = g_new0 (BDLVMSEGdata *, n_segs+1);
1221 16 : i = 0;
1222 16 : g_variant_iter_init (&iter, prop);
1223 32 : while (g_variant_iter_next (&iter, "(&o@a(tts))", &pv, &pv_segs)) {
1224 16 : pv_name_prop = get_object_property (pv, PV_INTF, "Name", NULL);
1225 16 : if (pv_name_prop) {
1226 16 : g_variant_get (pv_name_prop, "&s", &pv_name);
1227 16 : g_variant_iter_init (&iter2, pv_segs);
1228 33 : while (g_variant_iter_next (&iter2, "(tt&s)", &pv_first_pe, &pv_last_pe, NULL)) {
1229 17 : BDLVMSEGdata *seg = g_new0(BDLVMSEGdata, 1);
1230 17 : seg->pv_start_pe = pv_first_pe;
1231 17 : seg->size_pe = pv_last_pe - pv_first_pe + 1;
1232 17 : seg->pvdev = g_strdup (pv_name);
1233 17 : segs[i++] = seg;
1234 : }
1235 16 : g_variant_unref (pv_name_prop);
1236 : }
1237 16 : g_variant_unref (pv_segs);
1238 : }
1239 :
1240 16 : g_variant_unref (prop);
1241 16 : return segs;
1242 : }
1243 :
1244 24 : static void _lvm_data_and_metadata_lvs (const gchar *vg_name, const gchar *lv_name,
1245 : gchar ***data_lvs_ret, gchar ***metadata_lvs_ret,
1246 : GError **error) {
1247 : GVariant *prop;
1248 : gsize n_hidden_lvs;
1249 : gchar **data_lvs;
1250 : gchar **metadata_lvs;
1251 : GVariantIter iter, iter2;
1252 : int i_data;
1253 : int i_metadata;
1254 : const gchar *sublv;
1255 : GVariant *sublv_roles_prop;
1256 : GVariant *sublv_name_prop;
1257 : gchar *sublv_name;
1258 : const gchar *role;
1259 :
1260 24 : prop = get_lv_property (vg_name, lv_name, "HiddenLvs", error);
1261 24 : if (!prop) {
1262 0 : *data_lvs_ret = NULL;
1263 0 : *metadata_lvs_ret = NULL;
1264 0 : return;
1265 : }
1266 :
1267 24 : n_hidden_lvs = g_variant_n_children (prop);
1268 24 : data_lvs = g_new0(gchar *, n_hidden_lvs + 1);
1269 24 : metadata_lvs = g_new0(gchar *, n_hidden_lvs + 1);
1270 :
1271 24 : i_data = 0;
1272 24 : i_metadata = 0;
1273 24 : g_variant_iter_init (&iter, prop);
1274 64 : while (g_variant_iter_next (&iter, "&o", &sublv)) {
1275 16 : sublv_roles_prop = get_object_property (sublv, LV_INTF, "Roles", NULL);
1276 16 : if (sublv_roles_prop) {
1277 16 : sublv_name_prop = get_object_property (sublv, LV_INTF, "Name", NULL);
1278 16 : if (sublv_name_prop) {
1279 16 : g_variant_get (sublv_name_prop, "s", &sublv_name);
1280 16 : if (sublv_name) {
1281 16 : sublv_name = g_strstrip (g_strdelimit (sublv_name, "[]", ' '));
1282 16 : g_variant_iter_init (&iter2, sublv_roles_prop);
1283 48 : while (g_variant_iter_next (&iter2, "&s", &role)) {
1284 48 : if (g_strcmp0 (role, "image") == 0) {
1285 8 : data_lvs[i_data++] = sublv_name;
1286 8 : sublv_name = NULL;
1287 8 : break;
1288 40 : } else if (g_strcmp0 (role, "metadata") == 0) {
1289 8 : metadata_lvs[i_metadata++] = sublv_name;
1290 8 : sublv_name = NULL;
1291 8 : break;
1292 : }
1293 : }
1294 16 : g_free (sublv_name);
1295 : }
1296 16 : g_variant_unref (sublv_name_prop);
1297 : }
1298 16 : g_variant_unref (sublv_roles_prop);
1299 : }
1300 : }
1301 :
1302 24 : *data_lvs_ret = data_lvs;
1303 24 : *metadata_lvs_ret = metadata_lvs;
1304 :
1305 24 : g_variant_unref (prop);
1306 24 : return;
1307 : }
1308 :
1309 88 : static BDLVMLVdata* get_lv_data_from_props (GVariant *props, GError **error G_GNUC_UNUSED) {
1310 88 : BDLVMLVdata *data = g_new0 (BDLVMLVdata, 1);
1311 : GVariantDict dict;
1312 88 : GVariant *value = NULL;
1313 88 : gchar *path = NULL;
1314 88 : GVariant *name = NULL;
1315 88 : gsize n_children = 0;
1316 88 : gsize i = 0;
1317 88 : gchar **roles = NULL;
1318 88 : gchar **tags = NULL;
1319 :
1320 88 : g_variant_dict_init (&dict, props);
1321 :
1322 88 : g_variant_dict_lookup (&dict, "Name", "s", &(data->lv_name));
1323 88 : g_variant_dict_lookup (&dict, "Uuid", "s", &(data->uuid));
1324 88 : g_variant_dict_lookup (&dict, "Attr", "s", &(data->attr));
1325 88 : g_variant_dict_lookup (&dict, "SizeBytes", "t", &(data->size));
1326 88 : g_variant_dict_lookup (&dict, "DataPercent", "u", &(data->data_percent));
1327 88 : g_variant_dict_lookup (&dict, "MetaDataPercent", "u", &(data->metadata_percent));
1328 88 : g_variant_dict_lookup (&dict, "CopyPercent", "u", &(data->copy_percent));
1329 :
1330 : /* XXX: how to deal with LVs with multiple segment types? We are just taking
1331 : the first one now. */
1332 88 : value = g_variant_dict_lookup_value (&dict, "SegType", (GVariantType*) "as");
1333 88 : if (value) {
1334 : const gchar *st;
1335 88 : g_variant_get_child (value, 0, "&s", &st);
1336 88 : if (g_strcmp0 (st, "error") == 0)
1337 2 : st = "linear";
1338 88 : data->segtype = g_strdup (st);
1339 88 : g_variant_unref (value);
1340 : }
1341 :
1342 88 : value = g_variant_dict_lookup_value (&dict, "Roles", (GVariantType*) "as");
1343 88 : if (value) {
1344 88 : n_children = g_variant_n_children (value);
1345 88 : roles = g_new0 (gchar*, n_children + 1);
1346 248 : for (i=0; i < n_children; i++)
1347 160 : g_variant_get_child (value, i, "&s", roles+i);
1348 88 : data->roles = g_strjoinv (",", roles);
1349 88 : g_free (roles);
1350 88 : g_variant_unref (value);
1351 : }
1352 :
1353 : /* returns an object path for the VG */
1354 88 : g_variant_dict_lookup (&dict, "Vg", "o", &path);
1355 88 : name = get_object_property (path, VG_INTF, "Name", NULL);
1356 88 : g_free (path);
1357 88 : g_variant_get (name, "s", &(data->vg_name));
1358 88 : g_variant_unref (name);
1359 :
1360 88 : g_variant_dict_lookup (&dict, "OriginLv", "o", &path);
1361 88 : if (g_strcmp0 (path, "/") != 0) {
1362 6 : name = get_object_property (path, LV_CMN_INTF, "Name", NULL);
1363 6 : g_variant_get (name, "s", &(data->origin));
1364 6 : g_variant_unref (name);
1365 : }
1366 88 : g_free (path);
1367 88 : path = NULL;
1368 :
1369 88 : g_variant_dict_lookup (&dict, "PoolLv", "o", &path);
1370 88 : if (g_strcmp0 (path, "/") != 0) {
1371 12 : name = get_object_property (path, LV_CMN_INTF, "Name", NULL);
1372 12 : g_variant_get (name, "s", &(data->pool_lv));
1373 12 : g_variant_unref (name);
1374 : }
1375 88 : g_free (path);
1376 88 : path = NULL;
1377 :
1378 88 : g_variant_dict_lookup (&dict, "MovePv", "o", &path);
1379 88 : if (path && g_strcmp0 (path, "/") != 0) {
1380 0 : name = get_object_property (path, PV_INTF, "Name", NULL);
1381 0 : g_variant_get (name, "s", &(data->move_pv));
1382 0 : g_variant_unref (name);
1383 : }
1384 88 : g_free (path);
1385 88 : path = NULL;
1386 :
1387 88 : value = g_variant_dict_lookup_value (&dict, "Tags", (GVariantType*) "as");
1388 88 : if (value) {
1389 88 : n_children = g_variant_n_children (value);
1390 88 : tags = g_new0 (gchar*, n_children + 1);
1391 94 : for (i=0; i < n_children; i++) {
1392 6 : g_variant_get_child (value, i, "s", tags+i);
1393 : }
1394 88 : data->lv_tags = tags;
1395 88 : g_variant_unref (value);
1396 : }
1397 :
1398 88 : g_variant_dict_clear (&dict);
1399 88 : g_variant_unref (props);
1400 :
1401 88 : return data;
1402 : }
1403 :
1404 9 : static BDLVMVDOPooldata* get_vdo_data_from_props (GVariant *props, GError **error G_GNUC_UNUSED) {
1405 9 : BDLVMVDOPooldata *data = g_new0 (BDLVMVDOPooldata, 1);
1406 : GVariantDict dict;
1407 9 : gchar *value = NULL;
1408 :
1409 9 : g_variant_dict_init (&dict, props);
1410 :
1411 9 : g_variant_dict_lookup (&dict, "OperatingMode", "s", &value);
1412 9 : if (g_strcmp0 (value, "recovering") == 0)
1413 0 : data->operating_mode = BD_LVM_VDO_MODE_RECOVERING;
1414 9 : else if (g_strcmp0 (value, "read-only") == 0)
1415 0 : data->operating_mode = BD_LVM_VDO_MODE_READ_ONLY;
1416 9 : else if (g_strcmp0 (value, "normal") == 0)
1417 9 : data->operating_mode = BD_LVM_VDO_MODE_NORMAL;
1418 : else {
1419 0 : bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Unknown VDO operating mode: %s", value);
1420 0 : data->operating_mode = BD_LVM_VDO_MODE_UNKNOWN;
1421 : }
1422 9 : g_free (value);
1423 9 : value = NULL;
1424 :
1425 9 : g_variant_dict_lookup (&dict, "CompressionState", "s", &value);
1426 9 : if (g_strcmp0 (value, "online") == 0)
1427 7 : data->compression_state = BD_LVM_VDO_COMPRESSION_ONLINE;
1428 2 : else if (g_strcmp0 (value, "offline") == 0)
1429 2 : data->compression_state = BD_LVM_VDO_COMPRESSION_OFFLINE;
1430 : else {
1431 0 : bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Unknown VDO compression state: %s", value);
1432 0 : data->compression_state = BD_LVM_VDO_COMPRESSION_UNKNOWN;
1433 : }
1434 9 : g_free (value);
1435 9 : value = NULL;
1436 :
1437 9 : g_variant_dict_lookup (&dict, "IndexState", "s", &value);
1438 9 : if (g_strcmp0 (value, "error") == 0)
1439 0 : data->index_state = BD_LVM_VDO_INDEX_ERROR;
1440 9 : else if (g_strcmp0 (value, "closed") == 0)
1441 0 : data->index_state = BD_LVM_VDO_INDEX_CLOSED;
1442 9 : else if (g_strcmp0 (value, "opening") == 0)
1443 6 : data->index_state = BD_LVM_VDO_INDEX_OPENING;
1444 3 : else if (g_strcmp0 (value, "closing") == 0)
1445 1 : data->index_state = BD_LVM_VDO_INDEX_CLOSING;
1446 2 : else if (g_strcmp0 (value, "offline") == 0)
1447 0 : data->index_state = BD_LVM_VDO_INDEX_OFFLINE;
1448 2 : else if (g_strcmp0 (value, "online") == 0)
1449 2 : data->index_state = BD_LVM_VDO_INDEX_ONLINE;
1450 : else {
1451 0 : bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Unknown VDO index state: %s", value);
1452 0 : data->index_state = BD_LVM_VDO_INDEX_UNKNOWN;
1453 : }
1454 9 : g_free (value);
1455 9 : value = NULL;
1456 :
1457 9 : g_variant_dict_lookup (&dict, "WritePolicy", "s", &value);
1458 9 : if (g_strcmp0 (value, "auto") == 0)
1459 8 : data->write_policy = BD_LVM_VDO_WRITE_POLICY_AUTO;
1460 1 : else if (g_strcmp0 (value, "sync") == 0)
1461 1 : data->write_policy = BD_LVM_VDO_WRITE_POLICY_SYNC;
1462 0 : else if (g_strcmp0 (value, "async") == 0)
1463 0 : data->write_policy = BD_LVM_VDO_WRITE_POLICY_ASYNC;
1464 : else {
1465 0 : bd_utils_log_format (BD_UTILS_LOG_DEBUG, "Unknown VDO write policy: %s", value);
1466 0 : data->write_policy = BD_LVM_VDO_WRITE_POLICY_UNKNOWN;
1467 : }
1468 9 : g_free (value);
1469 9 : value = NULL;
1470 :
1471 9 : g_variant_dict_lookup (&dict, "UsedSize", "t", &(data->used_size));
1472 9 : g_variant_dict_lookup (&dict, "SavingPercent", "d", &(data->saving_percent));
1473 :
1474 9 : g_variant_dict_lookup (&dict, "IndexMemorySize", "t", &(data->index_memory_size));
1475 :
1476 9 : g_variant_dict_lookup (&dict, "Compression", "s", &value);
1477 9 : if (value && g_strcmp0 (value, "enabled") == 0)
1478 7 : data->compression = TRUE;
1479 : else
1480 2 : data->compression = FALSE;
1481 9 : g_free (value);
1482 9 : value = NULL;
1483 :
1484 9 : g_variant_dict_lookup (&dict, "Deduplication", "s", &value);
1485 9 : if (value && g_strcmp0 (value, "enabled") == 0)
1486 8 : data->deduplication = TRUE;
1487 : else
1488 1 : data->deduplication = FALSE;
1489 9 : g_free (value);
1490 9 : value = NULL;
1491 :
1492 9 : g_variant_dict_clear (&dict);
1493 9 : g_variant_unref (props);
1494 :
1495 9 : return data;
1496 : }
1497 :
1498 60 : static GVariant* create_size_str_param (guint64 size, const gchar *unit) {
1499 60 : gchar *str = NULL;
1500 :
1501 60 : str = g_strdup_printf ("%"G_GUINT64_FORMAT"%s", size, unit ? unit : "");
1502 60 : return g_variant_new_take_string (str);
1503 : }
1504 :
1505 : /**
1506 : * bd_lvm_pvcreate:
1507 : * @device: the device to make PV from
1508 : * @data_alignment: data (first PE) alignment or 0 to use the default
1509 : * @metadata_size: size of the area reserved for metadata or 0 to use the default
1510 : * @extra: (nullable) (array zero-terminated=1): extra options for the PV creation
1511 : * (just passed to LVM as is)
1512 : * @error: (out) (optional): place to store error (if any)
1513 : *
1514 : * Returns: whether the PV was successfully created or not
1515 : *
1516 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_CREATE
1517 : */
1518 83 : gboolean bd_lvm_pvcreate (const gchar *device, guint64 data_alignment, guint64 metadata_size, const BDExtraArg **extra, GError **error) {
1519 : GVariantBuilder builder;
1520 83 : GVariant *param = NULL;
1521 83 : GVariant *params = NULL;
1522 83 : GVariant *extra_params = NULL;
1523 :
1524 83 : if (data_alignment != 0 || metadata_size != 0) {
1525 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
1526 1 : if (data_alignment != 0) {
1527 1 : param = create_size_str_param (data_alignment, "b");
1528 1 : g_variant_builder_add (&builder, "{sv}", "dataalignment", param);
1529 : }
1530 :
1531 1 : if (metadata_size != 0) {
1532 1 : param = create_size_str_param (metadata_size, "b");
1533 1 : g_variant_builder_add (&builder, "{sv}", "metadatasize", param);
1534 : }
1535 1 : extra_params = g_variant_builder_end (&builder);
1536 1 : g_variant_builder_clear (&builder);
1537 : }
1538 :
1539 83 : params = g_variant_new ("(s)", device);
1540 :
1541 83 : return call_lvm_method_sync (MANAGER_OBJ, MANAGER_INTF, "PvCreate", params, extra_params, extra, TRUE, error);
1542 : }
1543 :
1544 : /**
1545 : * bd_lvm_pvresize:
1546 : * @device: the device to resize
1547 : * @size: the new requested size of the PV or 0 if it should be adjusted to device's size
1548 : * @extra: (nullable) (array zero-terminated=1): extra options for the PV resize
1549 : * (just passed to LVM as is)
1550 : * @error: (out) (optional): place to store error (if any)
1551 : *
1552 : * Returns: whether the PV's size was successfully changed or not
1553 : *
1554 : * If given @size different from 0, sets the PV's size to the given value (see
1555 : * pvresize(8)). If given @size 0, adjusts the PV's size to the underlying
1556 : * block device's size.
1557 : *
1558 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
1559 : */
1560 4 : gboolean bd_lvm_pvresize (const gchar *device, guint64 size, const BDExtraArg **extra, GError **error) {
1561 4 : GVariant *params = NULL;
1562 4 : gchar *obj_path = get_object_path (device, error);
1563 4 : if (!obj_path)
1564 2 : return FALSE;
1565 :
1566 2 : params = g_variant_new ("(t)", size);
1567 2 : return call_lvm_method_sync (obj_path, PV_INTF, "ReSize", params, NULL, extra, TRUE, error);
1568 : }
1569 :
1570 : /**
1571 : * bd_lvm_pvremove:
1572 : * @device: the PV device to be removed/destroyed
1573 : * @extra: (nullable) (array zero-terminated=1): extra options for the PV removal
1574 : * (just passed to LVM as is)
1575 : * @error: (out) (optional): place to store error (if any)
1576 : *
1577 : * Returns: whether the PV was successfully removed/destroyed or not
1578 : *
1579 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_REMOVE
1580 : */
1581 154 : gboolean bd_lvm_pvremove (const gchar *device, const BDExtraArg **extra, GError **error) {
1582 : GVariantBuilder builder;
1583 154 : GVariant *params = NULL;
1584 154 : GError *l_error = NULL;
1585 154 : gboolean ret = FALSE;
1586 :
1587 154 : if (access (device, F_OK) != 0) {
1588 2 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOEXIST,
1589 : "The device '%s' doesn't exist", device);
1590 2 : return FALSE;
1591 : }
1592 :
1593 : /* one has to be really persuasive to remove a PV (the double --force is not
1594 : bug, at least not in this code) */
1595 152 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
1596 152 : g_variant_builder_add (&builder, "{sv}", "-ff", g_variant_new ("s", ""));
1597 152 : g_variant_builder_add (&builder, "{sv}", "--yes", g_variant_new ("s", ""));
1598 :
1599 152 : params = g_variant_builder_end (&builder);
1600 152 : g_variant_builder_clear (&builder);
1601 152 : ret = call_lvm_obj_method_sync (device, PV_INTF, "Remove", NULL, params, extra, TRUE, &l_error);
1602 152 : if (!ret && l_error && g_error_matches (l_error, BD_LVM_ERROR, BD_LVM_ERROR_NOEXIST)) {
1603 : /* if the object doesn't exist, the given device is not a PV and thus
1604 : this function should be a noop */
1605 71 : g_clear_error (&l_error);
1606 71 : ret = TRUE;
1607 : }
1608 :
1609 152 : if (l_error)
1610 0 : g_propagate_error (error, l_error);
1611 152 : return ret;
1612 : }
1613 :
1614 : /**
1615 : * bd_lvm_pvmove:
1616 : * @src: the PV device to move extents off of
1617 : * @dest: (nullable): the PV device to move extents onto or %NULL
1618 : * @extra: (nullable) (array zero-terminated=1): extra options for the PV move
1619 : * (just passed to LVM as is)
1620 : * @error: (out) (optional): place to store error (if any)
1621 : *
1622 : * Returns: whether the extents from the @src PV where successfully moved or not
1623 : *
1624 : * If @dest is %NULL, VG allocation rules are used for the extents from the @src
1625 : * PV (see pvmove(8)).
1626 : *
1627 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
1628 : */
1629 1 : gboolean bd_lvm_pvmove (const gchar *src, const gchar *dest, const BDExtraArg **extra, GError **error) {
1630 1 : GVariant *prop = NULL;
1631 1 : gchar *src_path = NULL;
1632 1 : gchar *dest_path = NULL;
1633 1 : gchar *vg_obj_path = NULL;
1634 : GVariantBuilder builder;
1635 1 : GVariantType *type = NULL;
1636 1 : GVariant *dest_var = NULL;
1637 1 : GVariant *params = NULL;
1638 1 : GError *l_error = NULL;
1639 1 : gboolean ret = FALSE;
1640 :
1641 1 : src_path = get_object_path (src, &l_error);
1642 1 : if (!src_path || (g_strcmp0 (src_path, "/") == 0)) {
1643 0 : if (!l_error)
1644 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOEXIST,
1645 : "The source PV '%s' doesn't exist", src);
1646 : else
1647 0 : g_propagate_error (error, l_error);
1648 0 : return FALSE;
1649 : }
1650 1 : if (dest) {
1651 1 : dest_path = get_object_path (dest, &l_error);
1652 1 : if (!dest_path || (g_strcmp0 (dest_path, "/") == 0)) {
1653 0 : if (!l_error)
1654 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOEXIST,
1655 : "The destination PV '%s' doesn't exist", dest);
1656 : else
1657 0 : g_propagate_error (error, l_error);
1658 0 : return FALSE;
1659 : }
1660 : }
1661 1 : prop = get_object_property (src_path, PV_INTF, "Vg", error);
1662 1 : if (!prop) {
1663 0 : g_free (src_path);
1664 0 : return FALSE;
1665 : }
1666 1 : g_variant_get (prop, "o", &vg_obj_path);
1667 :
1668 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
1669 1 : g_variant_builder_add_value (&builder, g_variant_new ("o", src_path));
1670 1 : g_variant_builder_add_value (&builder, g_variant_new ("(tt)", (guint64) 0, (guint64) 0));
1671 1 : if (dest) {
1672 1 : dest_var = g_variant_new ("(ott)", dest_path, (guint64) 0, (guint64) 0);
1673 1 : g_variant_builder_add_value (&builder, g_variant_new_array (NULL, &dest_var, 1));
1674 : } else {
1675 0 : type = g_variant_type_new ("a(ott)");
1676 0 : g_variant_builder_add_value (&builder, g_variant_new_array (type, NULL, 0));
1677 0 : g_variant_type_free (type);
1678 : }
1679 1 : params = g_variant_builder_end (&builder);
1680 1 : g_variant_builder_clear (&builder);
1681 :
1682 1 : ret = call_lvm_method_sync (vg_obj_path, VG_INTF, "Move", params, NULL, extra, TRUE, error);
1683 :
1684 1 : g_free (src_path);
1685 1 : g_free (dest_path);
1686 1 : g_free (vg_obj_path);
1687 1 : return ret;
1688 : }
1689 :
1690 : /**
1691 : * bd_lvm_pvscan:
1692 : * @device: (nullable): the device to scan for PVs or %NULL
1693 : * @update_cache: whether to update the lvmetad cache or not
1694 : * @extra: (nullable) (array zero-terminated=1): extra options for the PV scan
1695 : * (just passed to LVM as is)
1696 : * @error: (out) (optional): place to store error (if any)
1697 : *
1698 : * Returns: whether the system or @device was successfully scanned for PVs or not
1699 : *
1700 : * The @device argument is used only if @update_cache is %TRUE. Otherwise the
1701 : * whole system is scanned for PVs.
1702 : *
1703 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
1704 : */
1705 5 : gboolean bd_lvm_pvscan (const gchar *device, gboolean update_cache, const BDExtraArg **extra, GError **error) {
1706 : GVariantBuilder builder;
1707 5 : GVariantType *type = NULL;
1708 5 : GVariant *params = NULL;
1709 5 : GVariant *device_var = NULL;
1710 :
1711 5 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
1712 : /* update the cache and specify the device (if any) */
1713 5 : g_variant_builder_add_value (&builder, g_variant_new_boolean (FALSE));
1714 5 : g_variant_builder_add_value (&builder, g_variant_new_boolean (update_cache));
1715 5 : if (update_cache && device) {
1716 1 : device_var = g_variant_new ("s", device);
1717 1 : g_variant_builder_add_value (&builder, g_variant_new_array (NULL, &device_var, 1));
1718 : } else {
1719 4 : type = g_variant_type_new ("as");
1720 4 : g_variant_builder_add_value (&builder, g_variant_new_array (type, NULL, 0));
1721 4 : g_variant_type_free (type);
1722 : }
1723 : /* (major, minor)`s, we never specify them */
1724 5 : type = g_variant_type_new ("a(ii)");
1725 5 : g_variant_builder_add_value (&builder, g_variant_new_array (type, NULL, 0));
1726 5 : g_variant_type_free (type);
1727 :
1728 5 : params = g_variant_builder_end (&builder);
1729 5 : g_variant_builder_clear (&builder);
1730 :
1731 5 : return call_lvm_method_sync (MANAGER_OBJ, MANAGER_INTF, "PvScan", params, NULL, extra, TRUE, error);
1732 : }
1733 :
1734 :
1735 9 : static gboolean _manage_lvm_tags (const gchar *objpath, const gchar *pv_path, const gchar *intf, const gchar **tags, const gchar *func, GError **error) {
1736 9 : guint num_tags = g_strv_length ((gchar **) tags);
1737 9 : GVariant *params = NULL;
1738 9 : GVariant **tags_array = NULL;
1739 : GVariantBuilder builder;
1740 9 : GVariant *pv_var = NULL;
1741 9 : gboolean ret = FALSE;
1742 :
1743 9 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
1744 :
1745 9 : if (pv_path) {
1746 : /* PV tags are set from the VG interface so we need to add the PV as an argument here */
1747 3 : pv_var = g_variant_new ("o", pv_path);
1748 3 : g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_OBJECT_PATH, &pv_var, 1));
1749 : }
1750 :
1751 9 : tags_array = g_new0 (GVariant *, num_tags + 1);
1752 27 : for (guint i = 0; i < num_tags; i++)
1753 18 : tags_array[i] = g_variant_new_string (tags[i]);
1754 :
1755 9 : g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_STRING, tags_array, num_tags));
1756 :
1757 9 : params = g_variant_builder_end (&builder);
1758 9 : g_variant_builder_clear (&builder);
1759 :
1760 9 : ret = call_lvm_method_sync (objpath, intf, func, params, NULL, NULL, TRUE, error);
1761 9 : g_free (tags_array);
1762 9 : return ret;
1763 : }
1764 :
1765 : /**
1766 : * bd_lvm_add_pv_tags:
1767 : * @device: the device to set PV tags for
1768 : * @tags: (array zero-terminated=1): list of tags to add
1769 : * @error: (out) (optional): place to store error (if any)
1770 : *
1771 : * Returns: whether the tags were successfully added to @device or not
1772 : *
1773 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
1774 : */
1775 3 : gboolean bd_lvm_add_pv_tags (const gchar *device, const gchar **tags, GError **error) {
1776 3 : BDLVMPVdata *pvinfo = NULL;
1777 3 : g_autofree gchar *vg_path = NULL;
1778 3 : g_autofree gchar *pv_path = NULL;
1779 :
1780 3 : pv_path = get_object_path (device, error);
1781 3 : if (!pv_path)
1782 0 : return FALSE;
1783 :
1784 3 : pvinfo = bd_lvm_pvinfo (device, error);
1785 3 : if (!pvinfo)
1786 0 : return FALSE;
1787 :
1788 3 : if (!pvinfo->vg_name) {
1789 1 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_FAIL,
1790 : "Tags can't be added to PVs without a VG");
1791 1 : bd_lvm_pvdata_free (pvinfo);
1792 1 : return FALSE;
1793 : }
1794 :
1795 2 : vg_path = get_object_path (pvinfo->vg_name, error);
1796 2 : bd_lvm_pvdata_free (pvinfo);
1797 2 : if (!vg_path)
1798 0 : return FALSE;
1799 :
1800 2 : return _manage_lvm_tags (vg_path, pv_path, VG_INTF, tags, "PvTagsAdd", error);
1801 : }
1802 :
1803 : /**
1804 : * bd_lvm_delete_pv_tags:
1805 : * @device: the device to set PV tags for
1806 : * @tags: (array zero-terminated=1): list of tags to remove
1807 : * @error: (out) (optional): place to store error (if any)
1808 : *
1809 : * Returns: whether the tags were successfully removed from @device or not
1810 : *
1811 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
1812 : */
1813 2 : gboolean bd_lvm_delete_pv_tags (const gchar *device, const gchar **tags, GError **error) {
1814 2 : BDLVMPVdata *pvinfo = NULL;
1815 2 : g_autofree gchar *vg_path = NULL;
1816 2 : g_autofree gchar *pv_path = NULL;
1817 :
1818 2 : pv_path = get_object_path (device, error);
1819 2 : if (!pv_path)
1820 0 : return FALSE;
1821 :
1822 2 : pvinfo = bd_lvm_pvinfo (device, error);
1823 2 : if (!pvinfo)
1824 0 : return FALSE;
1825 :
1826 2 : if (!pvinfo->vg_name) {
1827 1 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_FAIL,
1828 : "Tags can't be removed from PVs without a VG");
1829 1 : bd_lvm_pvdata_free (pvinfo);
1830 1 : return FALSE;
1831 : }
1832 :
1833 1 : vg_path = get_object_path (pvinfo->vg_name, error);
1834 1 : bd_lvm_pvdata_free (pvinfo);
1835 1 : if (!vg_path)
1836 0 : return FALSE;
1837 :
1838 1 : return _manage_lvm_tags (vg_path, pv_path, VG_INTF, tags, "PvTagsDel", error);
1839 : }
1840 : /**
1841 : * bd_lvm_pvinfo:
1842 : * @device: a PV to get information about or %NULL
1843 : * @error: (out) (optional): place to store error (if any)
1844 : *
1845 : * Returns: (transfer full): information about the PV on the given @device or
1846 : * %NULL in case of error (the @error) gets populated in those cases)
1847 : *
1848 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
1849 : */
1850 14 : BDLVMPVdata* bd_lvm_pvinfo (const gchar *device, GError **error) {
1851 14 : GVariant *props = NULL;
1852 14 : BDLVMPVdata *ret = NULL;
1853 :
1854 14 : props = get_pv_properties (device, error);
1855 14 : if (!props)
1856 : /* the error is already populated */
1857 0 : return NULL;
1858 :
1859 14 : ret = get_pv_data_from_props (props, error);
1860 14 : g_variant_unref (props);
1861 :
1862 14 : return ret;
1863 : }
1864 :
1865 : /**
1866 : * bd_lvm_pvs:
1867 : * @error: (out) (optional): place to store error (if any)
1868 : *
1869 : * Returns: (array zero-terminated=1): information about PVs found in the system
1870 : *
1871 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
1872 : */
1873 4 : BDLVMPVdata** bd_lvm_pvs (GError **error) {
1874 4 : gchar **objects = NULL;
1875 4 : guint64 n_pvs = 0;
1876 4 : GVariant *props = NULL;
1877 4 : BDLVMPVdata **ret = NULL;
1878 4 : guint64 i = 0;
1879 4 : GError *l_error = NULL;
1880 :
1881 4 : objects = get_existing_objects (PV_OBJ_PREFIX, &l_error);
1882 4 : if (!objects) {
1883 0 : if (!l_error) {
1884 : /* no PVs */
1885 0 : ret = g_new0 (BDLVMPVdata*, 1);
1886 0 : ret[0] = NULL;
1887 0 : return ret;
1888 : } else {
1889 0 : g_propagate_error (error, l_error);
1890 0 : return NULL;
1891 : }
1892 : }
1893 :
1894 4 : n_pvs = g_strv_length ((gchar **) objects);
1895 :
1896 : /* now create the return value -- NULL-terminated array of BDLVMPVdata */
1897 4 : ret = g_new0 (BDLVMPVdata*, n_pvs + 1);
1898 10 : for (i=0; i < n_pvs; i++) {
1899 6 : props = get_object_properties (objects[i], PV_INTF, error);
1900 6 : if (!props) {
1901 0 : g_strfreev (objects);
1902 0 : g_free (ret);
1903 0 : return NULL;
1904 : }
1905 6 : ret[i] = get_pv_data_from_props (props, error);
1906 6 : g_variant_unref (props);
1907 6 : if (!(ret[i])) {
1908 0 : g_strfreev (objects);
1909 0 : g_free (ret);
1910 0 : return NULL;
1911 : }
1912 : }
1913 4 : ret[i] = NULL;
1914 :
1915 4 : g_strfreev (objects);
1916 4 : return ret;
1917 : }
1918 :
1919 : /**
1920 : * bd_lvm_vgcreate:
1921 : * @name: name of the newly created VG
1922 : * @pv_list: (array zero-terminated=1): list of PVs the newly created VG should use
1923 : * @pe_size: PE size or 0 if the default value should be used
1924 : * @extra: (nullable) (array zero-terminated=1): extra options for the VG creation
1925 : * (just passed to LVM as is)
1926 : * @error: (out) (optional): place to store error (if any)
1927 : *
1928 : * Returns: whether the VG @name was successfully created or not
1929 : *
1930 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_CREATE
1931 : */
1932 47 : gboolean bd_lvm_vgcreate (const gchar *name, const gchar **pv_list, guint64 pe_size, const BDExtraArg **extra, GError **error) {
1933 : GVariantBuilder builder;
1934 47 : gchar *path = NULL;
1935 47 : const gchar **pv = NULL;
1936 47 : GVariant *pvs = NULL;
1937 47 : GVariant *params = NULL;
1938 47 : GVariant *extra_params = NULL;
1939 :
1940 : /* build the array of PVs (object paths) */
1941 47 : g_variant_builder_init (&builder, G_VARIANT_TYPE_OBJECT_PATH_ARRAY);
1942 123 : for (pv=pv_list; *pv; pv++) {
1943 77 : path = get_object_path (*pv, error);
1944 77 : if (!path) {
1945 1 : g_variant_builder_clear (&builder);
1946 1 : return FALSE;
1947 : }
1948 76 : g_variant_builder_add_value (&builder, g_variant_new ("o", path));
1949 : }
1950 46 : pvs = g_variant_builder_end (&builder);
1951 46 : g_variant_builder_clear (&builder);
1952 :
1953 : /* build the params tuple */
1954 46 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
1955 46 : g_variant_builder_add_value (&builder, g_variant_new ("s", name));
1956 46 : g_variant_builder_add_value (&builder, pvs);
1957 46 : params = g_variant_builder_end (&builder);
1958 46 : g_variant_builder_clear (&builder);
1959 :
1960 : /* pe_size needs to go to extra_params params */
1961 46 : pe_size = RESOLVE_PE_SIZE (pe_size);
1962 46 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
1963 46 : g_variant_builder_add_value (&builder, g_variant_new ("{sv}", "--physicalextentsize", create_size_str_param (pe_size, "b")));
1964 46 : extra_params = g_variant_builder_end (&builder);
1965 46 : g_variant_builder_clear (&builder);
1966 :
1967 46 : return call_lvm_method_sync (MANAGER_OBJ, MANAGER_INTF, "VgCreate", params, extra_params, extra, TRUE, error);
1968 : }
1969 :
1970 : /**
1971 : * bd_lvm_vgremove:
1972 : * @vg_name: name of the to be removed VG
1973 : * @extra: (nullable) (array zero-terminated=1): extra options for the VG removal
1974 : * (just passed to LVM as is)
1975 : * @error: (out) (optional): place to store error (if any)
1976 : *
1977 : * Returns: whether the VG was successfully removed or not
1978 : *
1979 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_REMOVE
1980 : */
1981 50 : gboolean bd_lvm_vgremove (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
1982 50 : return call_lvm_obj_method_sync (vg_name, VG_INTF, "Remove", NULL, NULL, extra, TRUE, error);
1983 : }
1984 :
1985 : /**
1986 : * bd_lvm_vgrename:
1987 : * @old_vg_name: old name of the VG to rename
1988 : * @new_vg_name: new name for the @old_vg_name VG
1989 : * @extra: (nullable) (array zero-terminated=1): extra options for the VG rename
1990 : * (just passed to LVM as is)
1991 : * @error: (out) (optional): place to store error (if any)
1992 : *
1993 : * Returns: whether the VG was successfully renamed or not
1994 : *
1995 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
1996 : */
1997 3 : gboolean bd_lvm_vgrename (const gchar *old_vg_name, const gchar *new_vg_name, const BDExtraArg **extra, GError **error) {
1998 3 : GVariant *params = g_variant_new ("(s)", new_vg_name);
1999 3 : return call_lvm_obj_method_sync (old_vg_name, VG_INTF, "Rename", params, NULL, extra, TRUE, error);
2000 : }
2001 :
2002 : /**
2003 : * bd_lvm_vgactivate:
2004 : * @vg_name: name of the to be activated VG
2005 : * @extra: (nullable) (array zero-terminated=1): extra options for the VG activation
2006 : * (just passed to LVM as is)
2007 : * @error: (out) (optional): place to store error (if any)
2008 : *
2009 : * Returns: whether the VG was successfully activated or not
2010 : *
2011 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2012 : */
2013 3 : gboolean bd_lvm_vgactivate (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
2014 3 : GVariant *params = g_variant_new ("(t)", (guint64) 0);
2015 3 : return call_lvm_obj_method_sync (vg_name, VG_INTF, "Activate", params, NULL, extra, TRUE, error);
2016 : }
2017 :
2018 : /**
2019 : * bd_lvm_vgdeactivate:
2020 : * @vg_name: name of the to be deactivated VG
2021 : * @extra: (nullable) (array zero-terminated=1): extra options for the VG deactivation
2022 : * (just passed to LVM as is)
2023 : * @error: (out) (optional): place to store error (if any)
2024 : *
2025 : * Returns: whether the VG was successfully deactivated or not
2026 : *
2027 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2028 : */
2029 3 : gboolean bd_lvm_vgdeactivate (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
2030 3 : GVariant *params = g_variant_new ("(t)", (guint64) 0);
2031 3 : return call_lvm_obj_method_sync (vg_name, VG_INTF, "Deactivate", params, NULL, extra, TRUE, error);
2032 : }
2033 :
2034 : /**
2035 : * bd_lvm_vgextend:
2036 : * @vg_name: name of the to be extended VG
2037 : * @device: PV device to extend the @vg_name VG with
2038 : * @extra: (nullable) (array zero-terminated=1): extra options for the VG extension
2039 : * (just passed to LVM as is)
2040 : * @error: (out) (optional): place to store error (if any)
2041 : *
2042 : * Returns: whether the VG @vg_name was successfully extended with the given @device or not.
2043 : *
2044 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2045 : */
2046 4 : gboolean bd_lvm_vgextend (const gchar *vg_name, const gchar *device, const BDExtraArg **extra, GError **error) {
2047 4 : g_autofree gchar *pv = NULL;
2048 4 : GVariant *pv_var = NULL;
2049 4 : GVariant *pvs = NULL;
2050 4 : GVariant *params = NULL;
2051 :
2052 4 : pv = get_object_path (device, error);
2053 4 : if (!pv)
2054 1 : return FALSE;
2055 :
2056 3 : pv_var = g_variant_new ("o", pv);
2057 3 : pvs = g_variant_new_array (NULL, &pv_var, 1);
2058 3 : params = g_variant_new_tuple (&pvs, 1);
2059 3 : return call_lvm_obj_method_sync (vg_name, VG_INTF, "Extend", params, NULL, extra, TRUE, error);
2060 : }
2061 :
2062 : /**
2063 : * bd_lvm_vgreduce:
2064 : * @vg_name: name of the to be reduced VG
2065 : * @device: (nullable): PV device the @vg_name VG should be reduced of or %NULL
2066 : * if the VG should be reduced of the missing PVs
2067 : * @extra: (nullable) (array zero-terminated=1): extra options for the VG reduction
2068 : * (just passed to LVM as is)
2069 : * @error: (out) (optional): place to store error (if any)
2070 : *
2071 : * Returns: whether the VG @vg_name was successfully reduced of the given @device or not
2072 : *
2073 : * Note: This function does not move extents off of the PV before removing
2074 : * it from the VG. You must do that first by calling #bd_lvm_pvmove.
2075 : *
2076 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2077 : */
2078 4 : gboolean bd_lvm_vgreduce (const gchar *vg_name, const gchar *device, const BDExtraArg **extra, GError **error) {
2079 4 : g_autofree gchar *pv = NULL;
2080 : GVariantBuilder builder;
2081 4 : GVariantType *type = NULL;
2082 4 : GVariant *pv_var = NULL;
2083 4 : GVariant *params = NULL;
2084 4 : GVariant *extra_params = NULL;
2085 :
2086 4 : if (device) {
2087 2 : pv = get_object_path (device, error);
2088 2 : if (!pv)
2089 0 : return FALSE;
2090 : }
2091 :
2092 4 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
2093 4 : if (device) {
2094 : /* do not remove missing */
2095 2 : pv_var = g_variant_new ("o", pv);
2096 2 : g_variant_builder_add_value (&builder, g_variant_new_boolean (FALSE));
2097 2 : g_variant_builder_add_value (&builder, g_variant_new_array (NULL, &pv_var, 1));
2098 2 : params = g_variant_builder_end (&builder);
2099 2 : g_variant_builder_clear (&builder);
2100 : } else {
2101 : /* remove missing */
2102 2 : g_variant_builder_add_value (&builder, g_variant_new_boolean (TRUE));
2103 2 : type = g_variant_type_new ("ao");
2104 2 : g_variant_builder_add_value (&builder, g_variant_new_array (type, NULL, 0));
2105 2 : g_variant_type_free (type);
2106 2 : params = g_variant_builder_end (&builder);
2107 2 : g_variant_builder_clear (&builder);
2108 :
2109 2 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
2110 2 : g_variant_builder_add_value (&builder, g_variant_new ("{sv}", "--force", g_variant_new ("s", "")));
2111 2 : extra_params = g_variant_builder_end (&builder);
2112 2 : g_variant_builder_clear (&builder);
2113 : }
2114 :
2115 4 : return call_lvm_obj_method_sync (vg_name, VG_INTF, "Reduce", params, extra_params, extra, TRUE, error);
2116 : }
2117 :
2118 : /**
2119 : * bd_lvm_add_vg_tags:
2120 : * @vg_name: the VG to set tags on
2121 : * @tags: (array zero-terminated=1): list of tags to add
2122 : * @error: (out) (optional): place to store error (if any)
2123 : *
2124 : * Returns: whether the tags were successfully added to @vg_name or not
2125 : *
2126 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
2127 : */
2128 2 : gboolean bd_lvm_add_vg_tags (const gchar *vg_name, const gchar **tags, GError **error) {
2129 4 : g_autofree gchar *obj_path = get_object_path (vg_name, error);
2130 2 : if (!obj_path)
2131 0 : return FALSE;
2132 :
2133 2 : return _manage_lvm_tags (obj_path, NULL, VG_INTF, tags, "TagsAdd", error);
2134 : }
2135 :
2136 : /**
2137 : * bd_lvm_delete_vg_tags:
2138 : * @vg_name: the VG to set tags on
2139 : * @tags: (array zero-terminated=1): list of tags to remove
2140 : * @error: (out) (optional): place to store error (if any)
2141 : *
2142 : * Returns: whether the tags were successfully removed from @vg_name or not
2143 : *
2144 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
2145 : */
2146 1 : gboolean bd_lvm_delete_vg_tags (const gchar *vg_name, const gchar **tags, GError **error) {
2147 2 : g_autofree gchar *obj_path = get_object_path (vg_name, error);
2148 1 : if (!obj_path)
2149 0 : return FALSE;
2150 :
2151 1 : return _manage_lvm_tags (obj_path, NULL, VG_INTF, tags, "TagsDel", error);
2152 : }
2153 :
2154 0 : static gboolean _vglock_start_stop (const gchar *vg_name, gboolean start, const BDExtraArg **extra, GError **error) {
2155 : GVariantBuilder builder;
2156 0 : GVariant *params = NULL;
2157 :
2158 0 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
2159 0 : if (start)
2160 0 : g_variant_builder_add (&builder, "{sv}", "--lockstart", g_variant_new ("s", ""));
2161 : else
2162 0 : g_variant_builder_add (&builder, "{sv}", "--lockstop", g_variant_new ("s", ""));
2163 0 : params = g_variant_builder_end (&builder);
2164 0 : g_variant_builder_clear (&builder);
2165 :
2166 0 : return call_lvm_obj_method_sync (vg_name, VG_INTF, "Change", NULL, params, extra, TRUE, error);
2167 : }
2168 :
2169 : /**
2170 : * bd_lvm_vglock_start:
2171 : * @vg_name: a shared VG to start the lockspace in lvmlockd
2172 : * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command
2173 : * (just passed to LVM as is)
2174 : * @error: (out) (optional): place to store error (if any)
2175 : *
2176 : * Returns: whether the lock was successfully started for @vg_name or not
2177 : *
2178 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2179 : */
2180 0 : gboolean bd_lvm_vglock_start (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
2181 0 : return _vglock_start_stop (vg_name, TRUE, extra, error);
2182 : }
2183 :
2184 : /**
2185 : * bd_lvm_vglock_stop:
2186 : * @vg_name: a shared VG to stop the lockspace in lvmlockd
2187 : * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command
2188 : * (just passed to LVM as is)
2189 : * @error: (out) (optional): place to store error (if any)
2190 : *
2191 : * Returns: whether the lock was successfully stopped for @vg_name or not
2192 : *
2193 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2194 : */
2195 0 : gboolean bd_lvm_vglock_stop (const gchar *vg_name, const BDExtraArg **extra, GError **error) {
2196 0 : return _vglock_start_stop (vg_name, FALSE, extra, error);
2197 : }
2198 :
2199 : /**
2200 : * bd_lvm_vginfo:
2201 : * @vg_name: a VG to get information about
2202 : * @error: (out) (optional): place to store error (if any)
2203 : *
2204 : * Returns: (transfer full): information about the @vg_name VG or %NULL in case
2205 : * of error (the @error) gets populated in those cases)
2206 : *
2207 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
2208 : */
2209 6 : BDLVMVGdata* bd_lvm_vginfo (const gchar *vg_name, GError **error) {
2210 6 : GVariant *props = NULL;
2211 6 : BDLVMVGdata *ret = NULL;
2212 :
2213 6 : props = get_vg_properties (vg_name, error);
2214 6 : if (!props)
2215 : /* the error is already populated */
2216 0 : return NULL;
2217 :
2218 6 : ret = get_vg_data_from_props (props, error);
2219 6 : g_variant_unref (props);
2220 :
2221 6 : return ret;
2222 : }
2223 :
2224 : /**
2225 : * bd_lvm_vgs:
2226 : * @error: (out) (optional): place to store error (if any)
2227 : *
2228 : * Returns: (array zero-terminated=1): information about VGs found in the system
2229 : *
2230 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
2231 : */
2232 2 : BDLVMVGdata** bd_lvm_vgs (GError **error) {
2233 2 : gchar **objects = NULL;
2234 2 : guint64 n_vgs = 0;
2235 2 : GVariant *props = NULL;
2236 2 : BDLVMVGdata **ret = NULL;
2237 2 : guint64 i = 0;
2238 2 : GError *l_error = NULL;
2239 :
2240 2 : objects = get_existing_objects (VG_OBJ_PREFIX, &l_error);
2241 2 : if (!objects) {
2242 0 : if (!l_error) {
2243 : /* no VGs */
2244 0 : ret = g_new0 (BDLVMVGdata*, 1);
2245 0 : ret[0] = NULL;
2246 0 : return ret;
2247 : } else {
2248 0 : g_propagate_error (error, l_error);
2249 0 : return NULL;
2250 : }
2251 : }
2252 :
2253 2 : n_vgs = g_strv_length ((gchar **) objects);
2254 :
2255 : /* now create the return value -- NULL-terminated array of BDLVMVGdata */
2256 2 : ret = g_new0 (BDLVMVGdata*, n_vgs + 1);
2257 3 : for (i=0; i < n_vgs; i++) {
2258 1 : props = get_object_properties (objects[i], VG_INTF, error);
2259 1 : if (!props) {
2260 0 : g_strfreev (objects);
2261 0 : g_free (ret);
2262 0 : return NULL;
2263 : }
2264 1 : ret[i] = get_vg_data_from_props (props, error);
2265 1 : g_variant_unref (props);
2266 1 : if (!(ret[i])) {
2267 0 : g_strfreev (objects);
2268 0 : g_free (ret);
2269 0 : return NULL;
2270 : }
2271 : }
2272 2 : ret[i] = NULL;
2273 :
2274 2 : g_strfreev (objects);
2275 2 : return ret;
2276 : }
2277 :
2278 : /**
2279 : * bd_lvm_lvorigin:
2280 : * @vg_name: name of the VG containing the queried LV
2281 : * @lv_name: name of the queried LV
2282 : * @error: (out) (optional): place to store error (if any)
2283 : *
2284 : * Returns: (transfer full): the origin volume for the @vg_name/@lv_name LV or
2285 : * %NULL if failed to determine (@error) is set in those cases)
2286 : *
2287 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
2288 : */
2289 1 : gchar* bd_lvm_lvorigin (const gchar *vg_name, const gchar *lv_name, GError **error) {
2290 1 : GVariant *prop = NULL;
2291 1 : gchar *obj_path = NULL;
2292 1 : gchar *ret = NULL;
2293 :
2294 1 : prop = get_lv_property (vg_name, lv_name, "OriginLv", error);
2295 1 : if (!prop)
2296 0 : return NULL;
2297 1 : g_variant_get (prop, "o", &obj_path);
2298 1 : g_variant_unref (prop);
2299 :
2300 1 : if (g_strcmp0 (obj_path, "/") == 0) {
2301 : /* no origin LV */
2302 0 : g_free (obj_path);
2303 0 : return NULL;
2304 : }
2305 1 : prop = get_object_property (obj_path, LV_CMN_INTF, "Name", error);
2306 1 : if (!prop) {
2307 0 : g_free (obj_path);
2308 0 : return NULL;
2309 : }
2310 :
2311 1 : g_variant_get (prop, "s", &ret);
2312 1 : g_variant_unref (prop);
2313 :
2314 1 : return ret;
2315 : }
2316 :
2317 : /**
2318 : * bd_lvm_lvcreate:
2319 : * @vg_name: name of the VG to create a new LV in
2320 : * @lv_name: name of the to-be-created LV
2321 : * @size: requested size of the new LV
2322 : * @type: (nullable): type of the new LV ("striped", "raid1",..., see lvcreate (8))
2323 : * @pv_list: (nullable) (array zero-terminated=1): list of PVs the newly created LV should use or %NULL
2324 : * if not specified
2325 : * @extra: (nullable) (array zero-terminated=1): extra options for the LV creation
2326 : * (just passed to LVM as is)
2327 : * @error: (out) (optional): place to store error (if any)
2328 : *
2329 : * Returns: whether the given @vg_name/@lv_name LV was successfully created or not
2330 : *
2331 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_CREATE
2332 : */
2333 47 : 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) {
2334 : GVariantBuilder builder;
2335 47 : gchar *path = NULL;
2336 47 : const gchar **pv = NULL;
2337 47 : GVariant *pvs = NULL;
2338 47 : GVariantType *var_type = NULL;
2339 47 : GVariant *params = NULL;
2340 47 : GVariant *extra_params = NULL;
2341 :
2342 : /* build the array of PVs (object paths) */
2343 47 : if (pv_list && *pv_list) {
2344 44 : g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2345 91 : for (pv=pv_list; *pv; pv++) {
2346 48 : path = get_object_path (*pv, error);
2347 48 : if (!path) {
2348 1 : g_variant_builder_clear (&builder);
2349 1 : return FALSE;
2350 : }
2351 47 : g_variant_builder_add_value (&builder, g_variant_new ("(ott)", path, (guint64) 0, (guint64) 0));
2352 : }
2353 43 : pvs = g_variant_builder_end (&builder);
2354 43 : g_variant_builder_clear (&builder);
2355 : } else {
2356 3 : var_type = g_variant_type_new ("a(ott)");
2357 3 : pvs = g_variant_new_array (var_type, NULL, 0);
2358 3 : g_variant_type_free (var_type);
2359 : }
2360 :
2361 : /* build the params tuple */
2362 46 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
2363 46 : g_variant_builder_add_value (&builder, g_variant_new ("s", lv_name));
2364 46 : g_variant_builder_add_value (&builder, g_variant_new ("t", size));
2365 46 : g_variant_builder_add_value (&builder, pvs);
2366 46 : params = g_variant_builder_end (&builder);
2367 46 : g_variant_builder_clear (&builder);
2368 :
2369 46 : if (type) {
2370 : /* and now the extra_params params */
2371 3 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
2372 3 : if (pv_list && g_strcmp0 (type, "striped") == 0)
2373 1 : g_variant_builder_add_value (&builder, g_variant_new ("{sv}", "stripes", g_variant_new ("i", g_strv_length ((gchar **) pv_list))));
2374 : else
2375 2 : g_variant_builder_add_value (&builder, g_variant_new ("{sv}", "type", g_variant_new ("s", type)));
2376 3 : extra_params = g_variant_builder_end (&builder);
2377 3 : g_variant_builder_clear (&builder);
2378 : }
2379 :
2380 46 : return call_lvm_obj_method_sync (vg_name, VG_INTF, "LvCreate", params, extra_params, extra, TRUE, error);
2381 : }
2382 :
2383 : /**
2384 : * bd_lvm_lvremove:
2385 : * @vg_name: name of the VG containing the to-be-removed LV
2386 : * @lv_name: name of the to-be-removed LV
2387 : * @force: whether to force removal or not
2388 : * @extra: (nullable) (array zero-terminated=1): extra options for the LV removal
2389 : * (just passed to LVM as is)
2390 : * @error: (out) (optional): place to store error (if any)
2391 : *
2392 : * Returns: whether the @vg_name/@lv_name LV was successfully removed or not
2393 : *
2394 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_REMOVE
2395 : */
2396 55 : gboolean bd_lvm_lvremove (const gchar *vg_name, const gchar *lv_name, gboolean force, const BDExtraArg **extra, GError **error) {
2397 : GVariantBuilder builder;
2398 55 : GVariant *extra_params = NULL;
2399 :
2400 55 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
2401 : /* '--yes' is needed if DISCARD is enabled */
2402 55 : g_variant_builder_add (&builder, "{sv}", "--yes", g_variant_new ("s", ""));
2403 55 : if (force) {
2404 53 : g_variant_builder_add (&builder, "{sv}", "--force", g_variant_new ("s", ""));
2405 : }
2406 55 : extra_params = g_variant_builder_end (&builder);
2407 55 : g_variant_builder_clear (&builder);
2408 :
2409 55 : return call_lv_method_sync (vg_name, lv_name, "Remove", NULL, extra_params, extra, TRUE, error);
2410 : }
2411 :
2412 : /**
2413 : * bd_lvm_lvrename:
2414 : * @vg_name: name of the VG containing the to-be-renamed LV
2415 : * @lv_name: name of the to-be-renamed LV
2416 : * @new_name: new name for the @vg_name/@lv_name LV
2417 : * @extra: (nullable) (array zero-terminated=1): extra options for the LV rename
2418 : * (just passed to LVM as is)
2419 : * @error: (out) (optional): place to store error (if any)
2420 : *
2421 : * Returns: whether the @vg_name/@lv_name LV was successfully renamed to
2422 : * @vg_name/@new_name or not
2423 : *
2424 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2425 : */
2426 6 : gboolean bd_lvm_lvrename (const gchar *vg_name, const gchar *lv_name, const gchar *new_name, const BDExtraArg **extra, GError **error) {
2427 6 : GVariant *params = NULL;
2428 :
2429 6 : params = g_variant_new ("(s)", new_name);
2430 6 : return call_lv_method_sync (vg_name, lv_name, "Rename", params, NULL, extra, TRUE, error);
2431 : }
2432 :
2433 : /**
2434 : * bd_lvm_lvresize:
2435 : * @vg_name: name of the VG containing the to-be-resized LV
2436 : * @lv_name: name of the to-be-resized LV
2437 : * @size: the requested new size of the LV
2438 : * @extra: (nullable) (array zero-terminated=1): extra options for the LV resize
2439 : * (just passed to LVM as is)
2440 : * @error: (out) (optional): place to store error (if any)
2441 : *
2442 : * Returns: whether the @vg_name/@lv_name LV was successfully resized or not
2443 : *
2444 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2445 : */
2446 10 : gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 size, const BDExtraArg **extra, GError **error) {
2447 : GVariantBuilder builder;
2448 10 : GVariantType *type = NULL;
2449 10 : GVariant *params = NULL;
2450 10 : GVariant *extra_params = NULL;
2451 10 : gboolean success = FALSE;
2452 :
2453 10 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
2454 10 : g_variant_builder_add_value (&builder, g_variant_new ("t", size));
2455 10 : type = g_variant_type_new ("a(ott)");
2456 10 : g_variant_builder_add_value (&builder, g_variant_new_array (type, NULL, 0));
2457 10 : g_variant_type_free (type);
2458 10 : params = g_variant_builder_end (&builder);
2459 10 : g_variant_builder_clear (&builder);
2460 :
2461 : /* Starting with 2.03.19 we need to add an extra option to avoid
2462 : any filesystem related checks by lvresize.
2463 : */
2464 10 : success = bd_utils_check_util_version (deps[DEPS_LVM].name, LVM_VERSION_FSRESIZE,
2465 10 : deps[DEPS_LVM].ver_arg, deps[DEPS_LVM].ver_regexp, NULL);
2466 10 : if (success) {
2467 10 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
2468 10 : g_variant_builder_add (&builder, "{sv}", "--fs", g_variant_new ("s", "ignore"));
2469 10 : extra_params = g_variant_builder_end (&builder);
2470 10 : g_variant_builder_clear (&builder);
2471 : }
2472 :
2473 10 : return call_lv_method_sync (vg_name, lv_name, "Resize", params, extra_params, extra, TRUE, error);
2474 : }
2475 :
2476 : /**
2477 : * bd_lvm_lvrepair:
2478 : * @vg_name: name of the VG containing the to-be-repaired LV
2479 : * @lv_name: name of the to-be-repaired LV
2480 : * @pv_list: (array zero-terminated=1): list of PVs to be used for the repair
2481 : * @extra: (nullable) (array zero-terminated=1): extra options for the LV repair
2482 : * (just passed to LVM as is)
2483 : * @error: (out) (optional): place to store error (if any)
2484 : *
2485 : * Returns: whether the @vg_name/@lv_name LV was successfully repaired or not
2486 : *
2487 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2488 : */
2489 1 : gboolean bd_lvm_lvrepair (const gchar *vg_name, const gchar *lv_name, const gchar **pv_list,
2490 : const BDExtraArg **extra, GError **error) {
2491 : GVariantBuilder builder;
2492 1 : GVariant *params = NULL;
2493 1 : gchar *path = NULL;
2494 1 : const gchar **pv = NULL;
2495 1 : GVariant *pvs = NULL;
2496 :
2497 : /* build the array of PVs (object paths) */
2498 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE_OBJECT_PATH_ARRAY);
2499 2 : for (pv=pv_list; *pv; pv++) {
2500 1 : path = get_object_path (*pv, error);
2501 1 : if (!path) {
2502 0 : g_variant_builder_clear (&builder);
2503 0 : return FALSE;
2504 : }
2505 1 : g_variant_builder_add_value (&builder, g_variant_new ("o", path));
2506 : }
2507 1 : pvs = g_variant_builder_end (&builder);
2508 1 : g_variant_builder_clear (&builder);
2509 :
2510 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
2511 1 : g_variant_builder_add_value (&builder, pvs);
2512 1 : params = g_variant_builder_end (&builder);
2513 1 : g_variant_builder_clear (&builder);
2514 :
2515 1 : return call_lv_method_sync (vg_name, lv_name, "RepairRaidLv", params, NULL, extra, TRUE, error);
2516 :
2517 : return FALSE;
2518 : }
2519 :
2520 : /**
2521 : * bd_lvm_lvactivate:
2522 : * @vg_name: name of the VG containing the to-be-activated LV
2523 : * @lv_name: name of the to-be-activated LV
2524 : * @ignore_skip: whether to ignore the skip flag or not
2525 : * @shared: whether to activate the LV in shared mode (used for shared LVM setups with lvmlockd,
2526 : * use %FALSE if not sure)
2527 : * @extra: (nullable) (array zero-terminated=1): extra options for the LV activation
2528 : * (just passed to LVM as is)
2529 : * @error: (out) (optional): place to store error (if any)
2530 : *
2531 : * Returns: whether the @vg_name/@lv_name LV was successfully activated or not
2532 : *
2533 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2534 : */
2535 6 : gboolean bd_lvm_lvactivate (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, gboolean shared, const BDExtraArg **extra, GError **error) {
2536 6 : GVariant *params = NULL;
2537 : GVariantBuilder builder;
2538 6 : GVariant *extra_params = NULL;
2539 :
2540 6 : if (shared)
2541 1 : params = g_variant_new ("(t)", (guint64) 1 << 6);
2542 : else
2543 5 : params = g_variant_new ("(t)", (guint64) 0);
2544 :
2545 6 : if (ignore_skip) {
2546 6 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
2547 6 : g_variant_builder_add (&builder, "{sv}", "-K", g_variant_new ("s", ""));
2548 6 : extra_params = g_variant_builder_end (&builder);
2549 6 : g_variant_builder_clear (&builder);
2550 : }
2551 :
2552 6 : return call_lv_method_sync (vg_name, lv_name, "Activate", params, extra_params, extra, TRUE, error);
2553 : }
2554 :
2555 : /**
2556 : * bd_lvm_lvdeactivate:
2557 : * @vg_name: name of the VG containing the to-be-deactivated LV
2558 : * @lv_name: name of the to-be-deactivated LV
2559 : * @extra: (nullable) (array zero-terminated=1): extra options for the LV deactivation
2560 : * (just passed to LVM as is)
2561 : * @error: (out) (optional): place to store error (if any)
2562 : *
2563 : * Returns: whether the @vg_name/@lv_name LV was successfully deactivated or not
2564 : *
2565 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY
2566 : */
2567 13 : gboolean bd_lvm_lvdeactivate (const gchar *vg_name, const gchar *lv_name, const BDExtraArg **extra, GError **error) {
2568 13 : GVariant *params = g_variant_new ("(t)", (guint64) 0);
2569 13 : return call_lv_method_sync (vg_name, lv_name, "Deactivate", params, NULL, extra, TRUE, error);
2570 : }
2571 :
2572 : /**
2573 : * bd_lvm_lvsnapshotcreate:
2574 : * @vg_name: name of the VG containing the LV a new snapshot should be created of
2575 : * @origin_name: name of the LV a new snapshot should be created of
2576 : * @snapshot_name: name of the to-be-created snapshot
2577 : * @size: requested size for the snapshot
2578 : * @extra: (nullable) (array zero-terminated=1): extra options for the LV snapshot creation
2579 : * (just passed to LVM as is)
2580 : * @error: (out) (optional): place to store error (if any)
2581 : *
2582 : * Returns: whether the @snapshot_name snapshot of the @vg_name/@origin_name LV
2583 : * was successfully created or not.
2584 : *
2585 : * Tech category: %BD_LVM_TECH_BASIC_SNAP-%BD_LVM_TECH_MODE_CREATE
2586 : */
2587 1 : gboolean bd_lvm_lvsnapshotcreate (const gchar *vg_name, const gchar *origin_name, const gchar *snapshot_name, guint64 size, const BDExtraArg **extra, GError **error) {
2588 : GVariantBuilder builder;
2589 1 : GVariant *params = NULL;
2590 :
2591 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
2592 1 : g_variant_builder_add_value (&builder, g_variant_new ("s", snapshot_name));
2593 1 : g_variant_builder_add_value (&builder, g_variant_new ("t", size));
2594 1 : params = g_variant_builder_end (&builder);
2595 1 : g_variant_builder_clear (&builder);
2596 :
2597 1 : return call_lv_method_sync (vg_name, origin_name, "Snapshot", params, NULL, extra, TRUE, error);
2598 : }
2599 :
2600 : /**
2601 : * bd_lvm_lvsnapshotmerge:
2602 : * @vg_name: name of the VG containing the to-be-merged LV snapshot
2603 : * @snapshot_name: name of the to-be-merged LV snapshot
2604 : * @extra: (nullable) (array zero-terminated=1): extra options for the LV snapshot merge
2605 : * (just passed to LVM as is)
2606 : * @error: (out) (optional): place to store error (if any)
2607 : *
2608 : * Returns: whether the @vg_name/@snapshot_name LV snapshot was successfully merged or not
2609 : *
2610 : * Tech category: %BD_LVM_TECH_BASIC_SNAP-%BD_LVM_TECH_MODE_MODIFY
2611 : */
2612 1 : gboolean bd_lvm_lvsnapshotmerge (const gchar *vg_name, const gchar *snapshot_name, const BDExtraArg **extra, GError **error) {
2613 1 : gchar *obj_id = NULL;
2614 1 : gchar *obj_path = NULL;
2615 :
2616 : /* get object path for vg_name/snapshot_name and call SNAP_INTF, "Merge" */
2617 1 : obj_id = g_strdup_printf ("%s/%s", vg_name, snapshot_name);
2618 1 : obj_path = get_object_path (obj_id, error);
2619 1 : g_free (obj_id);
2620 1 : if (!obj_path)
2621 0 : return FALSE;
2622 :
2623 1 : return call_lvm_method_sync (obj_path, SNAP_INTF, "Merge", NULL, NULL, extra, TRUE, error);
2624 : }
2625 :
2626 : /**
2627 : * bd_lvm_add_lv_tags:
2628 : * @vg_name: name of the VG that contains the LV to set tags on
2629 : * @lv_name: name of the LV to set tags on
2630 : * @tags: (array zero-terminated=1): list of tags to add
2631 : * @error: (out) (optional): place to store error (if any)
2632 : *
2633 : * Returns: whether the tags were successfully added to @device or not
2634 : *
2635 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
2636 : */
2637 2 : gboolean bd_lvm_add_lv_tags (const gchar *vg_name, const gchar *lv_name, const gchar **tags, GError **error) {
2638 2 : g_autofree gchar *obj_id = NULL;
2639 2 : g_autofree gchar *obj_path = NULL;
2640 :
2641 : /* get object path for vg_name/lv_name */
2642 2 : obj_id = g_strdup_printf ("%s/%s", vg_name, lv_name);
2643 2 : obj_path = get_object_path (obj_id, error);
2644 2 : if (!obj_path)
2645 0 : return FALSE;
2646 :
2647 2 : return _manage_lvm_tags (obj_path, NULL, LV_INTF, tags, "TagsAdd", error);
2648 : }
2649 :
2650 : /**
2651 : * bd_lvm_delete_lv_tags:
2652 : * @vg_name: name of the VG that contains the LV to set tags on
2653 : * @lv_name: name of the LV to set tags on
2654 : * @tags: (array zero-terminated=1): list of tags to remove
2655 : * @error: (out) (optional): place to store error (if any)
2656 : *
2657 : * Returns: whether the tags were successfully removed from @device or not
2658 : *
2659 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
2660 : */
2661 1 : gboolean bd_lvm_delete_lv_tags (const gchar *vg_name, const gchar *lv_name, const gchar **tags, GError **error) {
2662 1 : g_autofree gchar *obj_id = NULL;
2663 1 : g_autofree gchar *obj_path = NULL;
2664 :
2665 : /* get object path for vg_name/lv_name */
2666 1 : obj_id = g_strdup_printf ("%s/%s", vg_name, lv_name);
2667 1 : obj_path = get_object_path (obj_id, error);
2668 1 : if (!obj_path)
2669 0 : return FALSE;
2670 :
2671 1 : return _manage_lvm_tags (obj_path, NULL, LV_INTF, tags, "TagsDel", error);
2672 : }
2673 :
2674 : /**
2675 : * bd_lvm_lvinfo:
2676 : * @vg_name: name of the VG that contains the LV to get information about
2677 : * @lv_name: name of the LV to get information about
2678 : * @error: (out) (optional): place to store error (if any)
2679 : *
2680 : * Returns: (transfer full): information about the @vg_name/@lv_name LV or %NULL in case
2681 : * of error (the @error) gets populated in those cases)
2682 : *
2683 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
2684 : */
2685 37 : BDLVMLVdata* bd_lvm_lvinfo (const gchar *vg_name, const gchar *lv_name, GError **error) {
2686 37 : GVariant *props = NULL;
2687 37 : BDLVMLVdata* ret = NULL;
2688 :
2689 37 : props = get_lv_properties (vg_name, lv_name, error);
2690 37 : if (!props)
2691 : /* the error is already populated */
2692 0 : return NULL;
2693 :
2694 37 : ret = get_lv_data_from_props (props, error);
2695 37 : if (!ret)
2696 0 : return NULL;
2697 :
2698 67 : if (g_strcmp0 (ret->segtype, "thin-pool") == 0 ||
2699 30 : g_strcmp0 (ret->segtype, "cache-pool") == 0) {
2700 7 : ret->data_lv = _lvm_data_lv_name (vg_name, lv_name, NULL);
2701 7 : ret->metadata_lv = _lvm_metadata_lv_name (vg_name, lv_name, NULL);
2702 : }
2703 37 : if (g_strcmp0 (ret->segtype, "vdo-pool") == 0) {
2704 5 : ret->data_lv = _lvm_data_lv_name (vg_name, lv_name, NULL);
2705 : }
2706 :
2707 37 : return ret;
2708 : }
2709 :
2710 4 : BDLVMLVdata* bd_lvm_lvinfo_tree (const gchar *vg_name, const gchar *lv_name, GError **error) {
2711 4 : GVariant *props = NULL;
2712 4 : BDLVMLVdata* ret = NULL;
2713 :
2714 4 : props = get_lv_properties (vg_name, lv_name, error);
2715 4 : if (!props)
2716 : /* the error is already populated */
2717 0 : return NULL;
2718 :
2719 4 : ret = get_lv_data_from_props (props, error);
2720 4 : if (!ret)
2721 0 : return NULL;
2722 :
2723 8 : if (g_strcmp0 (ret->segtype, "thin-pool") == 0 ||
2724 4 : g_strcmp0 (ret->segtype, "cache-pool") == 0) {
2725 0 : ret->data_lv = _lvm_data_lv_name (vg_name, lv_name, NULL);
2726 0 : ret->metadata_lv = _lvm_metadata_lv_name (vg_name, lv_name, NULL);
2727 : }
2728 4 : if (g_strcmp0 (ret->segtype, "vdo-pool") == 0) {
2729 0 : ret->data_lv = _lvm_data_lv_name (vg_name, lv_name, NULL);
2730 : }
2731 4 : ret->segs = _lvm_segs (vg_name, lv_name, NULL);
2732 4 : _lvm_data_and_metadata_lvs (vg_name, lv_name, &ret->data_lvs, &ret->metadata_lvs, NULL);
2733 :
2734 4 : return ret;
2735 : }
2736 :
2737 46 : static gchar* get_lv_vg_name (const gchar *lv_obj_path, GError **error) {
2738 46 : GVariant *value = NULL;
2739 46 : gchar *vg_obj_path = NULL;
2740 46 : gchar *ret = NULL;
2741 :
2742 46 : value = get_object_property (lv_obj_path, LV_CMN_INTF, "Vg", error);
2743 46 : g_variant_get (value, "o", &vg_obj_path);
2744 46 : g_variant_unref (value);
2745 :
2746 46 : value = get_object_property (vg_obj_path, VG_INTF, "Name", error);
2747 46 : g_variant_get (value, "s", &ret);
2748 46 : g_free (vg_obj_path);
2749 46 : g_variant_unref (value);
2750 :
2751 46 : return ret;
2752 : }
2753 :
2754 : /**
2755 : * filter_lvs_by_vg: (skip)
2756 : *
2757 : * Filter LVs by VG name and prepend the matching ones to the @out list.
2758 : */
2759 90 : static gboolean filter_lvs_by_vg (gchar **lvs, const gchar *vg_name, GSList **out, guint64 *n_lvs, GError **error) {
2760 90 : gchar **lv_p = NULL;
2761 90 : gchar *lv_vg_name = NULL;
2762 90 : gboolean success = TRUE;
2763 :
2764 90 : if (!lvs)
2765 : /* nothing to do */
2766 0 : return TRUE;
2767 :
2768 137 : for (lv_p=lvs; *lv_p; lv_p++) {
2769 47 : if (vg_name) {
2770 46 : lv_vg_name = get_lv_vg_name (*lv_p, error);
2771 46 : if (!lv_vg_name) {
2772 0 : g_free (*lv_p);
2773 0 : success = FALSE;
2774 0 : continue;
2775 : }
2776 :
2777 46 : if (g_strcmp0 (lv_vg_name, vg_name) == 0) {
2778 46 : *out = g_slist_prepend (*out, *lv_p);
2779 46 : (*n_lvs)++;
2780 : } else {
2781 0 : g_free (*lv_p);
2782 : }
2783 :
2784 46 : g_free (lv_vg_name);
2785 : } else {
2786 1 : *out = g_slist_prepend (*out, *lv_p);
2787 1 : (*n_lvs)++;
2788 : }
2789 : }
2790 90 : return success;
2791 : }
2792 :
2793 : /**
2794 : * bd_lvm_lvs:
2795 : * @vg_name: (nullable): name of the VG to get information about LVs from
2796 : * @error: (out) (optional): place to store error (if any)
2797 : *
2798 : * Returns: (array zero-terminated=1): information about LVs found in the given
2799 : * @vg_name VG or in system if @vg_name is %NULL
2800 : *
2801 : * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_QUERY
2802 : */
2803 14 : BDLVMLVdata** bd_lvm_lvs (const gchar *vg_name, GError **error) {
2804 14 : gchar **lvs = NULL;
2805 14 : guint64 n_lvs = 0;
2806 14 : GVariant *props = NULL;
2807 14 : BDLVMLVdata **ret = NULL;
2808 14 : guint64 j = 0;
2809 14 : GSList *matched_lvs = NULL;
2810 14 : GSList *lv = NULL;
2811 14 : gboolean success = FALSE;
2812 14 : GError *l_error = NULL;
2813 :
2814 14 : lvs = get_existing_objects (LV_OBJ_PREFIX, &l_error);
2815 14 : if (!lvs && l_error) {
2816 0 : g_propagate_error (error, l_error);
2817 0 : return NULL;
2818 : }
2819 14 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
2820 14 : g_free (lvs);
2821 14 : if (!success) {
2822 0 : g_slist_free_full (matched_lvs, g_free);
2823 0 : return NULL;
2824 : }
2825 :
2826 14 : lvs = get_existing_objects (THIN_POOL_OBJ_PREFIX, &l_error);
2827 14 : if (!lvs && l_error) {
2828 0 : g_propagate_error (error, l_error);
2829 0 : g_slist_free_full (matched_lvs, g_free);
2830 0 : return NULL;
2831 : }
2832 14 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
2833 14 : g_free (lvs);
2834 14 : if (!success) {
2835 0 : g_slist_free_full (matched_lvs, g_free);
2836 0 : return NULL;
2837 : }
2838 :
2839 14 : lvs = get_existing_objects (CACHE_POOL_OBJ_PREFIX, &l_error);
2840 14 : if (!lvs && l_error) {
2841 0 : g_propagate_error (error, l_error);
2842 0 : g_slist_free_full (matched_lvs, g_free);
2843 0 : return NULL;
2844 : }
2845 14 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
2846 14 : g_free (lvs);
2847 14 : if (!success) {
2848 0 : g_slist_free_full (matched_lvs, g_free);
2849 0 : return NULL;
2850 : }
2851 :
2852 14 : lvs = get_existing_objects (VDO_POOL_OBJ_PREFIX, &l_error);
2853 14 : if (!lvs && l_error) {
2854 0 : g_propagate_error (error, l_error);
2855 0 : g_slist_free_full (matched_lvs, g_free);
2856 0 : return NULL;
2857 : }
2858 14 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
2859 14 : g_free (lvs);
2860 14 : if (!success) {
2861 0 : g_slist_free_full (matched_lvs, g_free);
2862 0 : return NULL;
2863 : }
2864 :
2865 14 : lvs = get_existing_objects (HIDDEN_LV_OBJ_PREFIX, &l_error);
2866 14 : if (!lvs && l_error) {
2867 0 : g_propagate_error (error, l_error);
2868 0 : g_slist_free_full (matched_lvs, g_free);
2869 0 : return NULL;
2870 : }
2871 14 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
2872 14 : g_free (lvs);
2873 14 : if (!success) {
2874 0 : g_slist_free_full (matched_lvs, g_free);
2875 0 : return NULL;
2876 : }
2877 :
2878 14 : if (n_lvs == 0) {
2879 : /* no LVs */
2880 2 : ret = g_new0 (BDLVMLVdata*, 1);
2881 2 : ret[0] = NULL;
2882 2 : g_slist_free_full (matched_lvs, g_free);
2883 2 : return ret;
2884 : }
2885 :
2886 : /* we have been prepending to the list so far, but it will be nicer if we
2887 : reverse it (to get back the original order) */
2888 12 : matched_lvs = g_slist_reverse (matched_lvs);
2889 :
2890 : /* now create the return value -- NULL-terminated array of BDLVMLVdata */
2891 12 : ret = g_new0 (BDLVMLVdata*, n_lvs + 1);
2892 :
2893 12 : lv = matched_lvs;
2894 39 : while (lv) {
2895 27 : props = get_object_properties (lv->data, LV_CMN_INTF, &l_error);
2896 27 : if (!props) {
2897 0 : g_slist_free_full (matched_lvs, g_free);
2898 0 : g_free (ret);
2899 0 : g_propagate_error (error, l_error);
2900 0 : return NULL;
2901 : }
2902 27 : ret[j] = get_lv_data_from_props (props, &l_error);
2903 27 : if (!(ret[j])) {
2904 0 : g_slist_free_full (matched_lvs, g_free);
2905 0 : for (guint64 i = 0; i < j; i++)
2906 0 : bd_lvm_lvdata_free (ret[i]);
2907 0 : g_free (ret);
2908 0 : g_propagate_error (error, l_error);
2909 0 : return NULL;
2910 53 : } else if ((g_strcmp0 (ret[j]->segtype, "thin-pool") == 0) ||
2911 26 : (g_strcmp0 (ret[j]->segtype, "cache-pool") == 0)) {
2912 3 : ret[j]->data_lv = _lvm_data_lv_name (ret[j]->vg_name, ret[j]->lv_name, &l_error);
2913 3 : ret[j]->metadata_lv = _lvm_metadata_lv_name (ret[j]->vg_name, ret[j]->lv_name, &l_error);
2914 24 : } else if (g_strcmp0 (ret[j]->segtype, "vdo-pool") == 0) {
2915 1 : ret[j]->data_lv = _lvm_data_lv_name (ret[j]->vg_name, ret[j]->lv_name, &l_error);
2916 : }
2917 27 : if (l_error) {
2918 0 : g_slist_free_full (matched_lvs, g_free);
2919 0 : for (guint64 i = 0; i <= j; i++)
2920 0 : bd_lvm_lvdata_free (ret[i]);
2921 0 : g_free (ret);
2922 0 : g_propagate_error (error, l_error);
2923 0 : return NULL;
2924 : }
2925 27 : j++;
2926 27 : lv = g_slist_next (lv);
2927 : }
2928 12 : g_slist_free_full (matched_lvs, g_free);
2929 :
2930 12 : ret[j] = NULL;
2931 12 : return ret;
2932 : }
2933 :
2934 4 : BDLVMLVdata** bd_lvm_lvs_tree (const gchar *vg_name, GError **error) {
2935 4 : gchar **lvs = NULL;
2936 4 : guint64 n_lvs = 0;
2937 4 : GVariant *props = NULL;
2938 4 : BDLVMLVdata **ret = NULL;
2939 4 : guint64 j = 0;
2940 4 : GSList *matched_lvs = NULL;
2941 4 : GSList *lv = NULL;
2942 4 : gboolean success = FALSE;
2943 4 : GError *l_error = NULL;
2944 :
2945 4 : lvs = get_existing_objects (LV_OBJ_PREFIX, &l_error);
2946 4 : if (!lvs && l_error) {
2947 0 : g_propagate_error (error, l_error);
2948 0 : return NULL;
2949 : }
2950 4 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
2951 4 : g_free (lvs);
2952 4 : if (!success) {
2953 0 : g_slist_free_full (matched_lvs, g_free);
2954 0 : return NULL;
2955 : }
2956 :
2957 4 : lvs = get_existing_objects (THIN_POOL_OBJ_PREFIX, &l_error);
2958 4 : if (!lvs && l_error) {
2959 0 : g_propagate_error (error, l_error);
2960 0 : g_slist_free_full (matched_lvs, g_free);
2961 0 : return NULL;
2962 : }
2963 4 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
2964 4 : g_free (lvs);
2965 4 : if (!success) {
2966 0 : g_slist_free_full (matched_lvs, g_free);
2967 0 : return NULL;
2968 : }
2969 :
2970 4 : lvs = get_existing_objects (CACHE_POOL_OBJ_PREFIX, &l_error);
2971 4 : if (!lvs && l_error) {
2972 0 : g_propagate_error (error, l_error);
2973 0 : g_slist_free_full (matched_lvs, g_free);
2974 0 : return NULL;
2975 : }
2976 4 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
2977 4 : g_free (lvs);
2978 4 : if (!success) {
2979 0 : g_slist_free_full (matched_lvs, g_free);
2980 0 : return NULL;
2981 : }
2982 :
2983 4 : lvs = get_existing_objects (VDO_POOL_OBJ_PREFIX, &l_error);
2984 4 : if (!lvs && l_error) {
2985 0 : g_propagate_error (error, l_error);
2986 0 : g_slist_free_full (matched_lvs, g_free);
2987 0 : return NULL;
2988 : }
2989 4 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
2990 4 : g_free (lvs);
2991 4 : if (!success) {
2992 0 : g_slist_free_full (matched_lvs, g_free);
2993 0 : return NULL;
2994 : }
2995 :
2996 4 : lvs = get_existing_objects (HIDDEN_LV_OBJ_PREFIX, &l_error);
2997 4 : if (!lvs && l_error) {
2998 0 : g_propagate_error (error, l_error);
2999 0 : g_slist_free_full (matched_lvs, g_free);
3000 0 : return NULL;
3001 : }
3002 4 : success = filter_lvs_by_vg (lvs, vg_name, &matched_lvs, &n_lvs, error);
3003 4 : g_free (lvs);
3004 4 : if (!success) {
3005 0 : g_slist_free_full (matched_lvs, g_free);
3006 0 : return NULL;
3007 : }
3008 :
3009 4 : if (n_lvs == 0) {
3010 : /* no LVs */
3011 0 : ret = g_new0 (BDLVMLVdata*, 1);
3012 0 : ret[0] = NULL;
3013 0 : g_slist_free_full (matched_lvs, g_free);
3014 0 : return ret;
3015 : }
3016 :
3017 : /* we have been prepending to the list so far, but it will be nicer if we
3018 : reverse it (to get back the original order) */
3019 4 : matched_lvs = g_slist_reverse (matched_lvs);
3020 :
3021 : /* now create the return value -- NULL-terminated array of BDLVMLVdata */
3022 4 : ret = g_new0 (BDLVMLVdata*, n_lvs + 1);
3023 :
3024 4 : lv = matched_lvs;
3025 24 : while (lv) {
3026 20 : props = get_object_properties (lv->data, LV_CMN_INTF, &l_error);
3027 20 : if (!props) {
3028 0 : g_slist_free_full (matched_lvs, g_free);
3029 0 : g_free (ret);
3030 0 : g_propagate_error (error, l_error);
3031 0 : return NULL;
3032 : }
3033 20 : ret[j] = get_lv_data_from_props (props, &l_error);
3034 20 : if (!(ret[j])) {
3035 0 : g_slist_free_full (matched_lvs, g_free);
3036 0 : for (guint64 i = 0; i < j; i++)
3037 0 : bd_lvm_lvdata_free (ret[i]);
3038 0 : g_free (ret);
3039 0 : g_propagate_error (error, l_error);
3040 0 : return NULL;
3041 40 : } else if ((g_strcmp0 (ret[j]->segtype, "thin-pool") == 0) ||
3042 20 : (g_strcmp0 (ret[j]->segtype, "cache-pool") == 0)) {
3043 0 : ret[j]->data_lv = _lvm_data_lv_name (ret[j]->vg_name, ret[j]->lv_name, &l_error);
3044 0 : ret[j]->metadata_lv = _lvm_metadata_lv_name (ret[j]->vg_name, ret[j]->lv_name, &l_error);
3045 20 : } else if (g_strcmp0 (ret[j]->segtype, "vdo-pool") == 0) {
3046 0 : ret[j]->data_lv = _lvm_data_lv_name (ret[j]->vg_name, ret[j]->lv_name, &l_error);
3047 : }
3048 20 : ret[j]->segs = _lvm_segs (ret[j]->vg_name, ret[j]->lv_name, &l_error);
3049 20 : _lvm_data_and_metadata_lvs (ret[j]->vg_name, ret[j]->lv_name, &ret[j]->data_lvs, &ret[j]->metadata_lvs,
3050 : &l_error);
3051 20 : if (l_error) {
3052 0 : g_slist_free_full (matched_lvs, g_free);
3053 0 : for (guint64 i = 0; i <= j; i++)
3054 0 : bd_lvm_lvdata_free (ret[i]);
3055 0 : g_free (ret);
3056 0 : g_propagate_error (error, l_error);
3057 0 : return NULL;
3058 : }
3059 20 : j++;
3060 20 : lv = g_slist_next (lv);
3061 : }
3062 4 : g_slist_free_full (matched_lvs, g_free);
3063 :
3064 4 : ret[j] = NULL;
3065 4 : return ret;
3066 : }
3067 :
3068 : /**
3069 : * bd_lvm_thpoolcreate:
3070 : * @vg_name: name of the VG to create a thin pool in
3071 : * @lv_name: name of the to-be-created pool LV
3072 : * @size: requested size of the to-be-created pool
3073 : * @md_size: requested metadata size or 0 to use the default
3074 : * @chunk_size: requested chunk size or 0 to use the default
3075 : * @profile: (nullable): profile to use (see lvm(8) for more information) or %NULL to use
3076 : * the default
3077 : * @extra: (nullable) (array zero-terminated=1): extra options for the thin pool creation
3078 : * (just passed to LVM as is)
3079 : * @error: (out) (optional): place to store error (if any)
3080 : *
3081 : * Returns: whether the @vg_name/@lv_name thin pool was successfully created or not
3082 : *
3083 : * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_CREATE
3084 : */
3085 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) {
3086 : GVariantBuilder builder;
3087 6 : GVariant *params = NULL;
3088 6 : GVariant *extra_params = NULL;
3089 6 : GVariant *param = NULL;
3090 :
3091 6 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3092 6 : g_variant_builder_add_value (&builder, g_variant_new ("s", lv_name));
3093 6 : g_variant_builder_add_value (&builder, g_variant_new_uint64 (size));
3094 6 : g_variant_builder_add_value (&builder, g_variant_new_boolean (TRUE));
3095 6 : params = g_variant_builder_end (&builder);
3096 6 : g_variant_builder_clear (&builder);
3097 :
3098 6 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
3099 6 : if (md_size != 0) {
3100 6 : param = create_size_str_param (md_size, "b");
3101 6 : g_variant_builder_add (&builder, "{sv}", "poolmetadatasize", param);
3102 : }
3103 6 : if (chunk_size != 0) {
3104 6 : param = create_size_str_param (chunk_size, "b");
3105 6 : g_variant_builder_add (&builder, "{sv}", "chunksize", param);
3106 : }
3107 6 : if (profile) {
3108 4 : g_variant_builder_add (&builder, "{sv}", "profile", g_variant_new ("s", profile));
3109 : }
3110 6 : extra_params = g_variant_builder_end (&builder);
3111 6 : g_variant_builder_clear (&builder);
3112 :
3113 6 : return call_lvm_obj_method_sync (vg_name, VG_INTF, "LvCreateLinear", params, extra_params, extra, TRUE, error);
3114 : }
3115 :
3116 : /**
3117 : * bd_lvm_thlvcreate:
3118 : * @vg_name: name of the VG containing the thin pool providing extents for the to-be-created thin LV
3119 : * @pool_name: name of the pool LV providing extents for the to-be-created thin LV
3120 : * @lv_name: name of the to-be-created thin LV
3121 : * @size: requested virtual size of the to-be-created thin LV
3122 : * @extra: (nullable) (array zero-terminated=1): extra options for the thin LV creation
3123 : * (just passed to LVM as is)
3124 : * @error: (out) (optional): place to store error (if any)
3125 : *
3126 : * Returns: whether the @vg_name/@lv_name thin LV was successfully created or not
3127 : *
3128 : * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_CREATE
3129 : */
3130 2 : gboolean bd_lvm_thlvcreate (const gchar *vg_name, const gchar *pool_name, const gchar *lv_name, guint64 size, const BDExtraArg **extra, GError **error) {
3131 : GVariantBuilder builder;
3132 2 : GVariant *params = NULL;
3133 :
3134 2 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3135 2 : g_variant_builder_add_value (&builder, g_variant_new ("s", lv_name));
3136 2 : g_variant_builder_add_value (&builder, g_variant_new ("t", size));
3137 2 : params = g_variant_builder_end (&builder);
3138 2 : g_variant_builder_clear (&builder);
3139 :
3140 2 : return call_thpool_method_sync (vg_name, pool_name, "LvCreate", params, NULL, extra, TRUE, error);
3141 : }
3142 :
3143 : /**
3144 : * bd_lvm_thlvpoolname:
3145 : * @vg_name: name of the VG containing the queried thin LV
3146 : * @lv_name: name of the queried thin LV
3147 : * @error: (out) (optional): place to store error (if any)
3148 : *
3149 : * Returns: (transfer full): the name of the pool volume for the @vg_name/@lv_name
3150 : * thin LV or %NULL if failed to determine (@error) is set in those cases)
3151 : *
3152 : * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_QUERY
3153 : */
3154 1 : gchar* bd_lvm_thlvpoolname (const gchar *vg_name, const gchar *lv_name, GError **error) {
3155 1 : GVariant *prop = NULL;
3156 1 : gboolean is_thin = FALSE;
3157 1 : gchar *pool_obj_path = NULL;
3158 1 : gchar *ret = NULL;
3159 :
3160 1 : prop = get_lv_property (vg_name, lv_name, "IsThinVolume", error);
3161 1 : if (!prop)
3162 0 : return NULL;
3163 1 : is_thin = g_variant_get_boolean (prop);
3164 1 : g_variant_unref (prop);
3165 :
3166 1 : if (!is_thin) {
3167 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOEXIST,
3168 : "The LV '%s' is not a thin LV and thus have no thin pool", lv_name);
3169 0 : return NULL;
3170 : }
3171 1 : prop = get_lv_property (vg_name, lv_name, "PoolLv", error);
3172 1 : if (!prop)
3173 0 : return NULL;
3174 1 : g_variant_get (prop, "o", &pool_obj_path);
3175 1 : g_variant_unref (prop);
3176 :
3177 1 : prop = get_object_property (pool_obj_path, LV_CMN_INTF, "Name", error);
3178 1 : g_free (pool_obj_path);
3179 1 : if (!prop)
3180 0 : return NULL;
3181 1 : g_variant_get (prop, "s", &ret);
3182 1 : g_variant_unref (prop);
3183 :
3184 1 : return ret;
3185 : }
3186 :
3187 : /**
3188 : * bd_lvm_thsnapshotcreate:
3189 : * @vg_name: name of the VG containing the thin LV a new snapshot should be created of
3190 : * @origin_name: name of the thin LV a new snapshot should be created of
3191 : * @snapshot_name: name of the to-be-created snapshot
3192 : * @pool_name: (nullable): name of the thin pool to create the snapshot in or %NULL if not specified
3193 : * @extra: (nullable) (array zero-terminated=1): extra options for the thin LV snapshot creation
3194 : * (just passed to LVM as is)
3195 : * @error: (out) (optional): place to store error (if any)
3196 : *
3197 : * Returns: whether the @snapshot_name snapshot of the @vg_name/@origin_name
3198 : * thin LV was successfully created or not.
3199 : *
3200 : * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_CREATE
3201 : */
3202 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) {
3203 : GVariantBuilder builder;
3204 1 : GVariant *params = NULL;
3205 1 : GVariant *extra_params = NULL;
3206 :
3207 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3208 1 : g_variant_builder_add_value (&builder, g_variant_new ("s", snapshot_name));
3209 1 : g_variant_builder_add_value (&builder, g_variant_new ("t", (guint64) 0));
3210 1 : params = g_variant_builder_end (&builder);
3211 1 : g_variant_builder_clear (&builder);
3212 :
3213 1 : if (pool_name) {
3214 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
3215 1 : g_variant_builder_add (&builder, "{sv}", "thinpool", g_variant_new ("s", pool_name));
3216 1 : extra_params = g_variant_builder_end (&builder);
3217 1 : g_variant_builder_clear (&builder);
3218 : }
3219 :
3220 1 : return call_lv_method_sync (vg_name, origin_name, "Snapshot", params, extra_params, extra, TRUE, error);
3221 : }
3222 :
3223 : /**
3224 : * get_lv_type_from_flags: (skip)
3225 : * @meta: getting type for a (future) metadata LV
3226 : *
3227 : * Get LV type string from flags.
3228 : */
3229 16 : static const gchar* get_lv_type_from_flags (BDLVMCachePoolFlags flags, gboolean meta, GError **error G_GNUC_UNUSED) {
3230 16 : if (!meta) {
3231 8 : if (flags & BD_LVM_CACHE_POOL_STRIPED)
3232 1 : return "striped";
3233 7 : else if (flags & BD_LVM_CACHE_POOL_RAID1)
3234 0 : return "raid1";
3235 7 : else if (flags & BD_LVM_CACHE_POOL_RAID5)
3236 0 : return "raid5";
3237 7 : else if (flags & BD_LVM_CACHE_POOL_RAID6)
3238 0 : return "raid6";
3239 7 : else if (flags & BD_LVM_CACHE_POOL_RAID10)
3240 0 : return "raid10";
3241 : else
3242 7 : return NULL;
3243 : } else {
3244 8 : if (flags & BD_LVM_CACHE_POOL_META_STRIPED)
3245 0 : return "striped";
3246 8 : else if (flags & BD_LVM_CACHE_POOL_META_RAID1)
3247 1 : return "raid1";
3248 7 : else if (flags & BD_LVM_CACHE_POOL_META_RAID5)
3249 0 : return "raid5";
3250 7 : else if (flags & BD_LVM_CACHE_POOL_META_RAID6)
3251 0 : return "raid6";
3252 7 : else if (flags & BD_LVM_CACHE_POOL_META_RAID10)
3253 0 : return "raid10";
3254 : else
3255 7 : return NULL;
3256 : }
3257 : }
3258 :
3259 : /**
3260 : * bd_lvm_cache_create_pool:
3261 : * @vg_name: name of the VG to create @pool_name in
3262 : * @pool_name: name of the cache pool LV to create
3263 : * @pool_size: desired size of the cache pool @pool_name
3264 : * @md_size: desired size of the @pool_name cache pool's metadata LV or 0 to
3265 : * use the default
3266 : * @mode: cache mode of the @pool_name cache pool
3267 : * @flags: a combination of (ORed) #BDLVMCachePoolFlags
3268 : * @fast_pvs: (array zero-terminated=1): list of (fast) PVs to create the @pool_name
3269 : * cache pool (and the metadata LV)
3270 : * @error: (out) (optional): place to store error (if any)
3271 : *
3272 : * Returns: whether the cache pool @vg_name/@pool_name was successfully created or not
3273 : *
3274 : * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_CREATE
3275 : */
3276 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) {
3277 8 : gboolean success = FALSE;
3278 8 : const gchar *type = NULL;
3279 8 : gchar *name = NULL;
3280 : GVariantBuilder builder;
3281 8 : GVariant *params = NULL;
3282 8 : GVariant *extra = NULL;
3283 8 : gchar *lv_id = NULL;
3284 8 : gchar *lv_obj_path = NULL;
3285 8 : const gchar *mode_str = NULL;
3286 8 : gchar *msg = NULL;
3287 8 : guint64 progress_id = 0;
3288 8 : GError *l_error = NULL;
3289 :
3290 8 : msg = g_strdup_printf ("Started 'create cache pool %s/%s'", vg_name, pool_name);
3291 8 : progress_id = bd_utils_report_started (msg);
3292 8 : g_free (msg);
3293 :
3294 : /* create an LV for the pool */
3295 8 : type = get_lv_type_from_flags (flags, FALSE, NULL);
3296 8 : success = bd_lvm_lvcreate (vg_name, pool_name, pool_size, type, fast_pvs, NULL, &l_error);
3297 8 : if (!success) {
3298 0 : g_prefix_error (&l_error, "Failed to create the pool LV: ");
3299 0 : bd_utils_report_finished (progress_id, l_error->message);
3300 0 : g_propagate_error (error, l_error);
3301 0 : return FALSE;
3302 : }
3303 :
3304 : /* 1/3 steps done */
3305 8 : bd_utils_report_progress (progress_id, 33, "Created the data LV");
3306 :
3307 : /* determine the size of the metadata LV */
3308 8 : type = get_lv_type_from_flags (flags, TRUE, NULL);
3309 8 : if (md_size == 0)
3310 7 : md_size = bd_lvm_cache_get_default_md_size (pool_size, NULL);
3311 8 : name = g_strdup_printf ("%s_meta", pool_name);
3312 :
3313 : /* create the metadata LV */
3314 8 : success = bd_lvm_lvcreate (vg_name, name, md_size, type, fast_pvs, NULL, &l_error);
3315 8 : if (!success) {
3316 0 : g_free (name);
3317 0 : g_prefix_error (&l_error, "Failed to create the pool metadata LV: ");
3318 0 : bd_utils_report_finished (progress_id, l_error->message);
3319 0 : g_propagate_error (error, l_error);
3320 0 : return FALSE;
3321 : }
3322 :
3323 : /* 2/3 steps done */
3324 8 : bd_utils_report_progress (progress_id, 66, "Created the metadata LV");
3325 :
3326 : /* create the cache pool from the two LVs */
3327 : /* build the params tuple */
3328 8 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3329 8 : lv_id = g_strdup_printf ("%s/%s", vg_name, name);
3330 8 : lv_obj_path = get_object_path (lv_id, &l_error);
3331 8 : g_free (lv_id);
3332 8 : if (!lv_obj_path) {
3333 0 : g_variant_builder_clear (&builder);
3334 0 : bd_utils_report_finished (progress_id, l_error->message);
3335 0 : g_propagate_error (error, l_error);
3336 0 : return FALSE;
3337 : }
3338 8 : g_variant_builder_add_value (&builder, g_variant_new ("o", lv_obj_path));
3339 8 : lv_id = g_strdup_printf ("%s/%s", vg_name, pool_name);
3340 8 : lv_obj_path = get_object_path (lv_id, &l_error);
3341 8 : g_free (lv_id);
3342 8 : if (!lv_obj_path) {
3343 0 : g_variant_builder_clear (&builder);
3344 0 : bd_utils_report_finished (progress_id, l_error->message);
3345 0 : g_propagate_error (error, l_error);
3346 0 : return FALSE;
3347 : }
3348 8 : g_variant_builder_add_value (&builder, g_variant_new ("o", lv_obj_path));
3349 8 : params = g_variant_builder_end (&builder);
3350 8 : g_variant_builder_clear (&builder);
3351 :
3352 : /* build the dictionary with the extra params */
3353 8 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
3354 8 : mode_str = bd_lvm_cache_get_mode_str (mode, &l_error);
3355 8 : if (!mode_str) {
3356 0 : g_variant_builder_clear (&builder);
3357 0 : bd_utils_report_finished (progress_id, l_error->message);
3358 0 : g_propagate_error (error, l_error);
3359 0 : return FALSE;
3360 : }
3361 8 : g_variant_builder_add (&builder, "{sv}", "cachemode", g_variant_new ("s", mode_str));
3362 8 : extra = g_variant_builder_end (&builder);
3363 8 : g_variant_builder_clear (&builder);
3364 :
3365 8 : success = call_lvm_obj_method_sync (vg_name, VG_INTF, "CreateCachePool", params, extra, NULL, TRUE, &l_error);
3366 8 : if (!success) {
3367 0 : bd_utils_report_finished (progress_id, l_error->message);
3368 0 : g_propagate_error (error, l_error);
3369 : } else
3370 8 : bd_utils_report_finished (progress_id, "Completed");
3371 :
3372 8 : return success;
3373 : }
3374 :
3375 : /**
3376 : * bd_lvm_cache_attach:
3377 : * @vg_name: name of the VG containing the @data_lv and the @cache_pool_lv LVs
3378 : * @data_lv: data LV to attach the @cache_pool_lv to
3379 : * @cache_pool_lv: cache pool LV to attach to the @data_lv
3380 : * @extra: (nullable) (array zero-terminated=1): extra options for the cache attachment
3381 : * (just passed to LVM as is)
3382 : * @error: (out) (optional): place to store error (if any)
3383 : *
3384 : * Returns: whether the @cache_pool_lv was successfully attached to the @data_lv or not
3385 : *
3386 : * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_MODIFY
3387 : */
3388 6 : gboolean bd_lvm_cache_attach (const gchar *vg_name, const gchar *data_lv, const gchar *cache_pool_lv, const BDExtraArg **extra, GError **error) {
3389 : GVariantBuilder builder;
3390 6 : GVariant *params = NULL;
3391 6 : gchar *lv_id = NULL;
3392 6 : g_autofree gchar *lv_obj_path = NULL;
3393 6 : gboolean ret = FALSE;
3394 :
3395 6 : lv_id = g_strdup_printf ("%s/%s", vg_name, data_lv);
3396 6 : lv_obj_path = get_object_path (lv_id, error);
3397 6 : g_free (lv_id);
3398 6 : if (!lv_obj_path)
3399 0 : return FALSE;
3400 6 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3401 6 : g_variant_builder_add_value (&builder, g_variant_new ("o", lv_obj_path));
3402 6 : params = g_variant_builder_end (&builder);
3403 6 : g_variant_builder_clear (&builder);
3404 :
3405 6 : lv_id = g_strdup_printf ("%s/%s", vg_name, cache_pool_lv);
3406 :
3407 6 : ret = call_lvm_obj_method_sync (lv_id, CACHE_POOL_INTF, "CacheLv", params, NULL, extra, TRUE, error);
3408 6 : g_free (lv_id);
3409 6 : return ret;
3410 : }
3411 :
3412 : /**
3413 : * bd_lvm_cache_detach:
3414 : * @vg_name: name of the VG containing the @cached_lv
3415 : * @cached_lv: name of the cached LV to detach its cache from
3416 : * @destroy: whether to destroy the cache after detach or not
3417 : * @extra: (nullable) (array zero-terminated=1): extra options for the cache detachment
3418 : * (just passed to LVM as is)
3419 : * @error: (out) (optional): place to store error (if any)
3420 : *
3421 : * Returns: whether the cache was successfully detached from the @cached_lv or not
3422 : *
3423 : * Note: synces the cache first
3424 : *
3425 : * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_MODIFY
3426 : */
3427 4 : gboolean bd_lvm_cache_detach (const gchar *vg_name, const gchar *cached_lv, gboolean destroy, const BDExtraArg **extra, GError **error) {
3428 4 : g_autofree gchar *lv_id = NULL;
3429 4 : g_autofree gchar *cache_pool_name = NULL;
3430 : GVariantBuilder builder;
3431 4 : GVariant *params = NULL;
3432 :
3433 4 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3434 4 : g_variant_builder_add_value (&builder, g_variant_new ("b", destroy));
3435 4 : params = g_variant_builder_end (&builder);
3436 4 : g_variant_builder_clear (&builder);
3437 :
3438 4 : cache_pool_name = bd_lvm_cache_pool_name (vg_name, cached_lv, error);
3439 4 : if (!cache_pool_name)
3440 0 : return FALSE;
3441 4 : lv_id = g_strdup_printf ("%s/%s", vg_name, cached_lv);
3442 4 : return call_lvm_obj_method_sync (lv_id, CACHED_LV_INTF, "DetachCachePool", params, NULL, extra, TRUE, error);
3443 : }
3444 :
3445 : /**
3446 : * bd_lvm_cache_create_cached_lv:
3447 : * @vg_name: name of the VG to create a cached LV in
3448 : * @lv_name: name of the cached LV to create
3449 : * @data_size: size of the data LV
3450 : * @cache_size: size of the cache (or cached LV more precisely)
3451 : * @md_size: size of the cache metadata LV or 0 to use the default
3452 : * @mode: cache mode for the cached LV
3453 : * @flags: a combination of (ORed) #BDLVMCachePoolFlags
3454 : * @slow_pvs: (array zero-terminated=1): list of slow PVs (used for the data LV)
3455 : * @fast_pvs: (array zero-terminated=1): list of fast PVs (used for the cache LV)
3456 : * @error: (out) (optional): place to store error (if any)
3457 : *
3458 : * Returns: whether the cached LV @lv_name was successfully created or not
3459 : *
3460 : * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_CREATE
3461 : */
3462 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,
3463 : const gchar **slow_pvs, const gchar **fast_pvs, GError **error) {
3464 1 : gboolean success = FALSE;
3465 1 : gchar *name = NULL;
3466 1 : gchar *msg = NULL;
3467 1 : guint64 progress_id = 0;
3468 1 : GError *l_error = NULL;
3469 :
3470 1 : msg = g_strdup_printf ("Started 'create cached LV %s/%s'", vg_name, lv_name);
3471 1 : progress_id = bd_utils_report_started (msg);
3472 1 : g_free (msg);
3473 :
3474 1 : success = bd_lvm_lvcreate (vg_name, lv_name, data_size, NULL, slow_pvs, NULL, &l_error);
3475 1 : if (!success) {
3476 0 : g_prefix_error (&l_error, "Failed to create the data LV: ");
3477 0 : bd_utils_report_finished (progress_id, l_error->message);
3478 0 : g_propagate_error (error, l_error);
3479 0 : return FALSE;
3480 : }
3481 :
3482 : /* 1/5 steps (cache pool creation has 3 steps) done */
3483 1 : bd_utils_report_progress (progress_id, 20, "Data LV created");
3484 :
3485 1 : name = g_strdup_printf ("%s_cache", lv_name);
3486 1 : success = bd_lvm_cache_create_pool (vg_name, name, cache_size, md_size, mode, flags, fast_pvs, &l_error);
3487 1 : if (!success) {
3488 0 : g_prefix_error (&l_error, "Failed to create the cache pool '%s': ", name);
3489 0 : g_free (name);
3490 0 : bd_utils_report_finished (progress_id, l_error->message);
3491 0 : g_propagate_error (error, l_error);
3492 0 : return FALSE;
3493 : }
3494 :
3495 : /* 4/5 steps (cache pool creation has 3 steps) done */
3496 1 : bd_utils_report_progress (progress_id, 80, "Cache pool created");
3497 :
3498 1 : success = bd_lvm_cache_attach (vg_name, lv_name, name, NULL, &l_error);
3499 1 : if (!success) {
3500 0 : g_prefix_error (&l_error, "Failed to attach the cache pool '%s' to the data LV: ", name);
3501 0 : g_free (name);
3502 0 : bd_utils_report_finished (progress_id, l_error->message);
3503 0 : g_propagate_error (error, l_error);
3504 0 : return FALSE;
3505 : }
3506 :
3507 1 : bd_utils_report_finished (progress_id, "Completed");
3508 1 : g_free (name);
3509 1 : return TRUE;
3510 : }
3511 :
3512 : /**
3513 : * bd_lvm_writecache_attach:
3514 : * @vg_name: name of the VG containing the @data_lv and the @cache_pool_lv LVs
3515 : * @data_lv: data LV to attach the @cache_lv to
3516 : * @cache_lv: cache (fast) LV to attach to the @data_lv
3517 : * @extra: (nullable) (array zero-terminated=1): extra options for the cache attachment
3518 : * (just passed to LVM as is)
3519 : * @error: (out) (optional): place to store error (if any)
3520 : *
3521 : * Returns: whether the @cache_lv was successfully attached to the @data_lv or not
3522 : *
3523 : * Note: Both @data_lv and @cache_lv will be deactivated before the operation.
3524 : *
3525 : * Tech category: %BD_LVM_TECH_WRITECACHE-%BD_LVM_TECH_MODE_MODIFY
3526 : */
3527 3 : gboolean bd_lvm_writecache_attach (const gchar *vg_name, const gchar *data_lv, const gchar *cache_lv, const BDExtraArg **extra, GError **error) {
3528 : GVariantBuilder builder;
3529 3 : GVariant *params = NULL;
3530 3 : gchar *lv_id = NULL;
3531 3 : g_autofree gchar *lv_obj_path = NULL;
3532 3 : gboolean success = FALSE;
3533 :
3534 : /* both LVs need to be inactive for the writecache convert to work */
3535 3 : success = bd_lvm_lvdeactivate (vg_name, data_lv, NULL, error);
3536 3 : if (!success)
3537 0 : return FALSE;
3538 :
3539 3 : success = bd_lvm_lvdeactivate (vg_name, cache_lv, NULL, error);
3540 3 : if (!success)
3541 0 : return FALSE;
3542 :
3543 3 : lv_id = g_strdup_printf ("%s/%s", vg_name, data_lv);
3544 3 : lv_obj_path = get_object_path (lv_id, error);
3545 3 : g_free (lv_id);
3546 3 : if (!lv_obj_path)
3547 0 : return FALSE;
3548 3 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3549 3 : g_variant_builder_add_value (&builder, g_variant_new ("o", lv_obj_path));
3550 3 : params = g_variant_builder_end (&builder);
3551 3 : g_variant_builder_clear (&builder);
3552 :
3553 3 : lv_id = g_strdup_printf ("%s/%s", vg_name, cache_lv);
3554 :
3555 3 : success = call_lvm_obj_method_sync (lv_id, LV_INTF, "WriteCacheLv", params, NULL, extra, TRUE, error);
3556 3 : g_free (lv_id);
3557 3 : return success;
3558 : }
3559 :
3560 : /**
3561 : * bd_lvm_writecache_detach:
3562 : * @vg_name: name of the VG containing the @cached_lv
3563 : * @cached_lv: name of the cached LV to detach its cache from
3564 : * @destroy: whether to destroy the cache after detach or not
3565 : * @extra: (nullable) (array zero-terminated=1): extra options for the cache detachment
3566 : * (just passed to LVM as is)
3567 : * @error: (out) (optional): place to store error (if any)
3568 : *
3569 : * Returns: whether the cache was successfully detached from the @cached_lv or not
3570 : *
3571 : * Note: synces the cache first
3572 : *
3573 : * Tech category: %BD_LVM_TECH_WRITECACHE-%BD_LVM_TECH_MODE_MODIFY
3574 : */
3575 2 : gboolean bd_lvm_writecache_detach (const gchar *vg_name, const gchar *cached_lv, gboolean destroy, const BDExtraArg **extra, GError **error) {
3576 2 : return bd_lvm_cache_detach (vg_name, cached_lv, destroy, extra, error);
3577 : }
3578 :
3579 : /**
3580 : * bd_lvm_writecache_create_cached_lv:
3581 : * @vg_name: name of the VG to create a cached LV in
3582 : * @lv_name: name of the cached LV to create
3583 : * @data_size: size of the data LV
3584 : * @cache_size: size of the cache (or cached LV more precisely)
3585 : * @slow_pvs: (array zero-terminated=1): list of slow PVs (used for the data LV)
3586 : * @fast_pvs: (array zero-terminated=1): list of fast PVs (used for the cache LV)
3587 : * @error: (out) (optional): place to store error (if any)
3588 : *
3589 : * Returns: whether the cached LV @lv_name was successfully created or not
3590 : *
3591 : * Tech category: %BD_LVM_TECH_WRITECACHE-%BD_LVM_TECH_MODE_CREATE
3592 : */
3593 1 : gboolean bd_lvm_writecache_create_cached_lv (const gchar *vg_name, const gchar *lv_name, guint64 data_size, guint64 cache_size,
3594 : const gchar **slow_pvs, const gchar **fast_pvs, GError **error) {
3595 1 : gboolean success = FALSE;
3596 1 : gchar *name = NULL;
3597 1 : gchar *msg = NULL;
3598 1 : guint64 progress_id = 0;
3599 1 : GError *l_error = NULL;
3600 :
3601 1 : msg = g_strdup_printf ("Started 'create cached LV %s/%s'", vg_name, lv_name);
3602 1 : progress_id = bd_utils_report_started (msg);
3603 1 : g_free (msg);
3604 :
3605 1 : name = g_strdup_printf ("%s_writecache", lv_name);
3606 1 : success = bd_lvm_lvcreate (vg_name, name, cache_size, NULL, fast_pvs, NULL, &l_error);
3607 1 : if (!success) {
3608 0 : g_prefix_error (&l_error, "Failed to create the cache LV '%s': ", name);
3609 0 : g_free (name);
3610 0 : bd_utils_report_finished (progress_id, l_error->message);
3611 0 : g_propagate_error (error, l_error);
3612 0 : return FALSE;
3613 : }
3614 :
3615 : /* 1/3 steps done */
3616 1 : bd_utils_report_progress (progress_id, 33, "Cache LV created");
3617 :
3618 1 : success = bd_lvm_lvcreate (vg_name, lv_name, data_size, NULL, slow_pvs, NULL, &l_error);
3619 1 : if (!success) {
3620 0 : g_prefix_error (&l_error, "Failed to create the data LV: ");
3621 0 : g_free (name);
3622 0 : bd_utils_report_finished (progress_id, l_error->message);
3623 0 : g_propagate_error (error, l_error);
3624 0 : return FALSE;
3625 : }
3626 :
3627 : /* 2/3 steps done */
3628 1 : bd_utils_report_progress (progress_id, 66, "Data LV created");
3629 :
3630 1 : success = bd_lvm_writecache_attach (vg_name, lv_name, name, NULL, &l_error);
3631 1 : if (!success) {
3632 0 : g_prefix_error (&l_error, "Failed to attach the cache LV '%s' to the data LV: ", name);
3633 0 : g_free (name);
3634 0 : bd_utils_report_finished (progress_id, l_error->message);
3635 0 : g_propagate_error (error, l_error);
3636 0 : return FALSE;
3637 : }
3638 :
3639 1 : bd_utils_report_finished (progress_id, "Completed");
3640 1 : g_free (name);
3641 1 : return TRUE;
3642 : }
3643 :
3644 : /**
3645 : * bd_lvm_cache_pool_name:
3646 : * @vg_name: name of the VG containing the @cached_lv
3647 : * @cached_lv: cached LV to get the name of the its pool LV for
3648 : * @error: (out) (optional): place to store error (if any)
3649 : *
3650 : * Returns: name of the cache pool LV used by the @cached_lv or %NULL in case of error
3651 : *
3652 : * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_QUERY
3653 : */
3654 5 : gchar* bd_lvm_cache_pool_name (const gchar *vg_name, const gchar *cached_lv, GError **error) {
3655 5 : gchar *ret = NULL;
3656 5 : gchar *name_start = NULL;
3657 5 : gchar *name_end = NULL;
3658 5 : gchar *pool_name = NULL;
3659 5 : gchar *lv_spec = NULL;
3660 5 : GVariant *prop = NULL;
3661 5 : gchar *pool_obj_path = NULL;
3662 :
3663 : /* same as for a thin LV, but with square brackets */
3664 5 : lv_spec = g_strdup_printf ("%s/%s", vg_name, cached_lv);
3665 5 : prop = get_lvm_object_property (lv_spec, CACHED_LV_INTF, "CachePool", error);
3666 5 : g_free (lv_spec);
3667 5 : if (!prop)
3668 0 : return NULL;
3669 5 : g_variant_get (prop, "o", &pool_obj_path);
3670 5 : prop = get_object_property (pool_obj_path, LV_CMN_INTF, "Name", error);
3671 5 : g_free (pool_obj_path);
3672 5 : if (!prop)
3673 0 : return NULL;
3674 5 : g_variant_get (prop, "s", &ret);
3675 5 : g_variant_unref (prop);
3676 :
3677 5 : name_start = strchr (ret, '[');
3678 5 : if (!name_start) {
3679 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_CACHE_INVAL,
3680 : "Failed to determine cache pool name from: '%s'", ret);
3681 0 : g_free (ret);
3682 0 : return NULL;
3683 : }
3684 5 : name_start++;
3685 :
3686 5 : name_end = strchr (ret, ']');
3687 5 : if (!name_end) {
3688 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_CACHE_INVAL,
3689 : "Failed to determine cache pool name from: '%s'", ret);
3690 0 : g_free (ret);
3691 0 : return NULL;
3692 : }
3693 :
3694 5 : pool_name = g_strndup (name_start, name_end - name_start);
3695 5 : g_free (ret);
3696 :
3697 5 : return pool_name;
3698 : }
3699 :
3700 : /**
3701 : * bd_lvm_thpool_convert:
3702 : * @vg_name: name of the VG to create the new thin pool in
3703 : * @data_lv: name of the LV that should become the data part of the new pool
3704 : * @metadata_lv: name of the LV that should become the metadata part of the new pool
3705 : * @name: (nullable): name for the thin pool (if %NULL, the name @data_lv is inherited)
3706 : * @extra: (nullable) (array zero-terminated=1): extra options for the thin pool creation
3707 : * (just passed to LVM as is)
3708 : * @error: (out) (optional): place to store error (if any)
3709 : *
3710 : * Converts the @data_lv and @metadata_lv into a new thin pool in the @vg_name
3711 : * VG.
3712 : *
3713 : * Returns: whether the new thin pool was successfully created from @data_lv and
3714 : * @metadata_lv or not
3715 : *
3716 : * Tech category: %BD_LVM_TECH_THIN-%BD_LVM_TECH_MODE_CREATE
3717 : */
3718 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) {
3719 : GVariantBuilder builder;
3720 1 : GVariant *params = NULL;
3721 1 : gchar *obj_id = NULL;
3722 1 : gchar *data_lv_path = NULL;
3723 1 : gchar *metadata_lv_path = NULL;
3724 1 : gboolean ret = FALSE;
3725 :
3726 1 : obj_id = g_strdup_printf ("%s/%s", vg_name, data_lv);
3727 1 : data_lv_path = get_object_path (obj_id, error);
3728 1 : g_free (obj_id);
3729 1 : if (!data_lv_path)
3730 0 : return FALSE;
3731 :
3732 1 : obj_id = g_strdup_printf ("%s/%s", vg_name, metadata_lv);
3733 1 : metadata_lv_path = get_object_path (obj_id, error);
3734 1 : g_free (obj_id);
3735 1 : if (!metadata_lv_path)
3736 0 : return FALSE;
3737 :
3738 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3739 1 : g_variant_builder_add_value (&builder, g_variant_new ("o", metadata_lv_path));
3740 1 : g_variant_builder_add_value (&builder, g_variant_new ("o", data_lv_path));
3741 1 : params = g_variant_builder_end (&builder);
3742 1 : g_variant_builder_clear (&builder);
3743 :
3744 1 : ret = call_lvm_obj_method_sync (vg_name, VG_INTF, "CreateThinPool", params, NULL, extra, TRUE, error);
3745 1 : if (ret && name)
3746 1 : bd_lvm_lvrename (vg_name, data_lv, name, NULL, error);
3747 1 : return ret;
3748 : }
3749 :
3750 : /**
3751 : * bd_lvm_cache_pool_convert:
3752 : * @vg_name: name of the VG to create the new thin pool in
3753 : * @data_lv: name of the LV that should become the data part of the new pool
3754 : * @metadata_lv: name of the LV that should become the metadata part of the new pool
3755 : * @name: (nullable): name for the thin pool (if %NULL, the name @data_lv is inherited)
3756 : * @extra: (nullable) (array zero-terminated=1): extra options for the thin pool creation
3757 : * (just passed to LVM as is)
3758 : * @error: (out) (optional): place to store error (if any)
3759 : *
3760 : * Converts the @data_lv and @metadata_lv into a new cache pool in the @vg_name
3761 : * VG.
3762 : *
3763 : * Returns: whether the new cache pool was successfully created from @data_lv and
3764 : * @metadata_lv or not
3765 : *
3766 : * Tech category: %BD_LVM_TECH_CACHE-%BD_LVM_TECH_MODE_CREATE
3767 : */
3768 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) {
3769 : GVariantBuilder builder;
3770 1 : GVariant *params = NULL;
3771 1 : gchar *obj_id = NULL;
3772 1 : gchar *data_lv_path = NULL;
3773 1 : gchar *metadata_lv_path = NULL;
3774 1 : gboolean ret = FALSE;
3775 :
3776 1 : obj_id = g_strdup_printf ("%s/%s", vg_name, data_lv);
3777 1 : data_lv_path = get_object_path (obj_id, error);
3778 1 : g_free (obj_id);
3779 1 : if (!data_lv_path)
3780 0 : return FALSE;
3781 :
3782 1 : obj_id = g_strdup_printf ("%s/%s", vg_name, metadata_lv);
3783 1 : metadata_lv_path = get_object_path (obj_id, error);
3784 1 : g_free (obj_id);
3785 1 : if (!metadata_lv_path)
3786 0 : return FALSE;
3787 :
3788 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3789 1 : g_variant_builder_add_value (&builder, g_variant_new ("o", metadata_lv_path));
3790 1 : g_variant_builder_add_value (&builder, g_variant_new ("o", data_lv_path));
3791 1 : params = g_variant_builder_end (&builder);
3792 1 : g_variant_builder_clear (&builder);
3793 :
3794 1 : ret = call_lvm_obj_method_sync (vg_name, VG_INTF, "CreateCachePool", params, NULL, extra, TRUE, error);
3795 :
3796 1 : if (!ret && name)
3797 0 : bd_lvm_lvrename (vg_name, data_lv, name, NULL, error);
3798 :
3799 1 : return ret;
3800 : }
3801 :
3802 : /**
3803 : * bd_lvm_vdo_pool_create:
3804 : * @vg_name: name of the VG to create a new LV in
3805 : * @lv_name: name of the to-be-created VDO LV
3806 : * @pool_name: (nullable): name of the to-be-created VDO pool LV or %NULL for default name
3807 : * @data_size: requested size of the data VDO LV (physical size of the @pool_name VDO pool LV)
3808 : * @virtual_size: requested virtual_size of the @lv_name VDO LV
3809 : * @index_memory: amount of index memory (in bytes) or 0 for default
3810 : * @compression: whether to enable compression or not
3811 : * @deduplication: whether to enable deduplication or not
3812 : * @write_policy: write policy for the volume
3813 : * @extra: (nullable) (array zero-terminated=1): extra options for the VDO LV creation
3814 : * (just passed to LVM as is)
3815 : * @error: (out) (optional): place to store error (if any)
3816 : *
3817 : * Returns: whether the given @vg_name/@lv_name VDO LV was successfully created or not
3818 : *
3819 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_CREATE
3820 : */
3821 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) {
3822 : GVariantBuilder builder;
3823 7 : GVariant *params = NULL;
3824 7 : GVariant *extra_params = NULL;
3825 7 : gchar *old_config = NULL;
3826 7 : const gchar *write_policy_str = NULL;
3827 7 : g_autofree gchar *name = NULL;
3828 7 : gboolean ret = FALSE;
3829 :
3830 7 : write_policy_str = bd_lvm_get_vdo_write_policy_str (write_policy, error);
3831 7 : if (write_policy_str == NULL)
3832 0 : return FALSE;
3833 :
3834 : /* build the params tuple */
3835 7 : g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
3836 :
3837 7 : if (!pool_name) {
3838 1 : name = g_strdup_printf ("%s_vpool", lv_name);
3839 1 : g_variant_builder_add_value (&builder, g_variant_new ("s", name));
3840 : } else
3841 6 : g_variant_builder_add_value (&builder, g_variant_new ("s", pool_name));
3842 :
3843 7 : g_variant_builder_add_value (&builder, g_variant_new ("s", lv_name));
3844 7 : g_variant_builder_add_value (&builder, g_variant_new ("t", data_size));
3845 7 : g_variant_builder_add_value (&builder, g_variant_new ("t", virtual_size));
3846 7 : params = g_variant_builder_end (&builder);
3847 7 : g_variant_builder_clear (&builder);
3848 :
3849 : /* and now the extra_params params */
3850 7 : g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY);
3851 7 : g_variant_builder_add_value (&builder, g_variant_new ("{sv}", "--compression", g_variant_new ("s", compression ? "y" : "n")));
3852 7 : g_variant_builder_add_value (&builder, g_variant_new ("{sv}", "--deduplication", g_variant_new ("s", deduplication ? "y" : "n")));
3853 7 : extra_params = g_variant_builder_end (&builder);
3854 7 : g_variant_builder_clear (&builder);
3855 :
3856 : /* index_memory and write_policy can be specified only using the config */
3857 7 : g_mutex_lock (&global_config_lock);
3858 7 : old_config = global_config_str;
3859 7 : if (index_memory != 0)
3860 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 : "",
3861 : index_memory / (1024 * 1024),
3862 : write_policy_str);
3863 : else
3864 4 : global_config_str = g_strdup_printf ("%s allocation {vdo_write_policy=\"%s\"}", old_config ? old_config : "",
3865 : write_policy_str);
3866 :
3867 7 : ret = call_lvm_obj_method_sync (vg_name, VG_VDO_INTF, "CreateVdoPoolandLv", params, extra_params, extra, FALSE, error);
3868 :
3869 7 : g_free (global_config_str);
3870 7 : global_config_str = old_config;
3871 7 : g_mutex_unlock (&global_config_lock);
3872 :
3873 7 : return ret;
3874 : }
3875 :
3876 : /**
3877 : * bd_lvm_vdo_enable_compression:
3878 : * @vg_name: name of the VG containing the to-be-changed VDO pool LV
3879 : * @pool_name: name of the VDO pool LV to enable compression on
3880 : * @extra: (nullable) (array zero-terminated=1): extra options for the VDO change
3881 : * (just passed to LVM as is)
3882 : * @error: (out) (optional): place to store error (if any)
3883 : *
3884 : * Returns: whether compression was successfully enabled on @vg_name/@pool_name LV or not
3885 : *
3886 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
3887 : */
3888 1 : gboolean bd_lvm_vdo_enable_compression (const gchar *vg_name, const gchar *pool_name, const BDExtraArg **extra, GError **error) {
3889 1 : return call_vdopool_method_sync (vg_name, pool_name, "EnableCompression", NULL, NULL, extra, TRUE, error);
3890 : }
3891 :
3892 : /**
3893 : * bd_lvm_vdo_disable_compression:
3894 : * @vg_name: name of the VG containing the to-be-changed VDO pool LV
3895 : * @pool_name: name of the VDO pool LV to disable compression on
3896 : * @extra: (nullable) (array zero-terminated=1): extra options for the VDO change
3897 : * (just passed to LVM as is)
3898 : * @error: (out) (optional): place to store error (if any)
3899 : *
3900 : * Returns: whether compression was successfully disabled on @vg_name/@pool_name LV or not
3901 : *
3902 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
3903 : */
3904 1 : gboolean bd_lvm_vdo_disable_compression (const gchar *vg_name, const gchar *pool_name, const BDExtraArg **extra, GError **error) {
3905 1 : return call_vdopool_method_sync (vg_name, pool_name, "DisableCompression", NULL, NULL, extra, TRUE, error);
3906 : }
3907 :
3908 : /**
3909 : * bd_lvm_vdo_enable_deduplication:
3910 : * @vg_name: name of the VG containing the to-be-changed VDO pool LV
3911 : * @pool_name: name of the VDO pool LV to enable deduplication on
3912 : * @extra: (nullable) (array zero-terminated=1): extra options for the VDO change
3913 : * (just passed to LVM as is)
3914 : * @error: (out) (optional): place to store error (if any)
3915 : *
3916 : * Returns: whether deduplication was successfully enabled on @vg_name/@pool_name LV or not
3917 : *
3918 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
3919 : */
3920 1 : gboolean bd_lvm_vdo_enable_deduplication (const gchar *vg_name, const gchar *pool_name, const BDExtraArg **extra, GError **error) {
3921 1 : return call_vdopool_method_sync (vg_name, pool_name, "EnableDeduplication", NULL, NULL, extra, TRUE, error);
3922 : }
3923 :
3924 : /**
3925 : * bd_lvm_vdo_enable_deduplication:
3926 : * @vg_name: name of the VG containing the to-be-changed VDO pool LV
3927 : * @pool_name: name of the VDO pool LV to disable deduplication on
3928 : * @extra: (nullable) (array zero-terminated=1): extra options for the VDO change
3929 : * (just passed to LVM as is)
3930 : * @error: (out) (optional): place to store error (if any)
3931 : *
3932 : * Returns: whether deduplication was successfully disabled on @vg_name/@pool_name LV or not
3933 : *
3934 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
3935 : */
3936 1 : gboolean bd_lvm_vdo_disable_deduplication (const gchar *vg_name, const gchar *pool_name, const BDExtraArg **extra, GError **error) {
3937 1 : return call_vdopool_method_sync (vg_name, pool_name, "DisableDeduplication", NULL, NULL, extra, TRUE, error);
3938 : }
3939 :
3940 : /**
3941 : * bd_lvm_vdo_info:
3942 : * @vg_name: name of the VG that contains the LV to get information about
3943 : * @pool_name: name of the VDO pool LV to get information about
3944 : * @error: (out) (optional): place to store error (if any)
3945 : *
3946 : * Returns: (transfer full): information about the @vg_name/@lv_name LV or %NULL in case
3947 : * of error (the @error) gets populated in those cases)
3948 : *
3949 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_QUERY
3950 : */
3951 9 : BDLVMVDOPooldata* bd_lvm_vdo_info (const gchar *vg_name, const gchar *pool_name, GError **error) {
3952 9 : GVariant *props = NULL;
3953 :
3954 9 : props = get_vdo_properties (vg_name, pool_name, error);
3955 9 : if (!props)
3956 : /* the error is already populated */
3957 0 : return NULL;
3958 :
3959 9 : return get_vdo_data_from_props (props, error);
3960 : }
3961 :
3962 : /**
3963 : * bd_lvm_vdo_resize:
3964 : * @vg_name: name of the VG containing the to-be-resized VDO LV
3965 : * @lv_name: name of the to-be-resized VDO LV
3966 : * @size: the requested new size of the VDO LV
3967 : * @extra: (nullable) (array zero-terminated=1): extra options for the VDO LV resize
3968 : * (just passed to LVM as is)
3969 : * @error: (out) (optional): place to store error (if any)
3970 : *
3971 : * Returns: whether the @vg_name/@lv_name VDO LV was successfully resized or not
3972 : *
3973 : * Note: Reduction needs to process TRIM for reduced disk area to unmap used data blocks
3974 : * from the VDO pool LV and it may take a long time.
3975 : *
3976 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
3977 : */
3978 1 : gboolean bd_lvm_vdo_resize (const gchar *vg_name, const gchar *lv_name, guint64 size, const BDExtraArg **extra, GError **error) {
3979 1 : return bd_lvm_lvresize (vg_name, lv_name, size, extra, error);
3980 : }
3981 :
3982 : /**
3983 : * bd_lvm_vdo_pool_resize:
3984 : * @vg_name: name of the VG containing the to-be-resized VDO pool LV
3985 : * @pool_name: name of the to-be-resized VDO pool LV
3986 : * @size: the requested new size of the VDO pool LV
3987 : * @extra: (nullable) (array zero-terminated=1): extra options for the VDO pool LV resize
3988 : * (just passed to LVM as is)
3989 : * @error: (out) (optional): place to store error (if any)
3990 : *
3991 : * Returns: whether the @vg_name/@pool_name VDO pool LV was successfully resized or not
3992 : *
3993 : * Note: Size of the VDO pool LV can be only extended, not reduced.
3994 : *
3995 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_MODIFY
3996 : */
3997 2 : gboolean bd_lvm_vdo_pool_resize (const gchar *vg_name, const gchar *pool_name, guint64 size, const BDExtraArg **extra, GError **error) {
3998 2 : BDLVMLVdata *info = NULL;
3999 :
4000 2 : info = bd_lvm_lvinfo (vg_name, pool_name, error);
4001 2 : if (!info)
4002 0 : return FALSE;
4003 :
4004 2 : if (info->size >= size) {
4005 1 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOT_SUPPORTED,
4006 : "Reducing physical size of the VDO pool LV is not supported.");
4007 1 : bd_lvm_lvdata_free (info);
4008 1 : return FALSE;
4009 : }
4010 :
4011 1 : bd_lvm_lvdata_free (info);
4012 :
4013 1 : return bd_lvm_lvresize (vg_name, pool_name, size, extra, error);
4014 : }
4015 :
4016 : /**
4017 : * bd_lvm_vdo_pool_convert:
4018 : * @vg_name: name of the VG that contains @pool_lv
4019 : * @pool_lv: name of the LV that should become the new VDO pool LV
4020 : * @name: (nullable): name for the VDO LV or %NULL for default name
4021 : * @virtual_size: virtual size for the new VDO LV
4022 : * @extra: (nullable) (array zero-terminated=1): extra options for the VDO pool creation
4023 : * (just passed to LVM as is)
4024 : * @error: (out) (optional): place to store error (if any)
4025 : *
4026 : * Converts the @pool_lv into a new VDO pool LV in the @vg_name VG and creates a new
4027 : * @name VDO LV with size @virtual_size.
4028 : *
4029 : * Note: All data on @pool_lv will be irreversibly destroyed.
4030 : *
4031 : * Returns: whether the new VDO pool LV was successfully created from @pool_lv and or not
4032 : *
4033 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_CREATE&%BD_LVM_TECH_MODE_MODIFY
4034 : */
4035 0 : gboolean bd_lvm_vdo_pool_convert (const gchar *vg_name G_GNUC_UNUSED, const gchar *pool_lv G_GNUC_UNUSED, const gchar *name G_GNUC_UNUSED,
4036 : guint64 virtual_size G_GNUC_UNUSED, guint64 index_memory G_GNUC_UNUSED, gboolean compression G_GNUC_UNUSED,
4037 : gboolean deduplication G_GNUC_UNUSED, BDLVMVDOWritePolicy write_policy G_GNUC_UNUSED,
4038 : const BDExtraArg **extra G_GNUC_UNUSED, GError **error) {
4039 0 : return bd_lvm_is_tech_avail (BD_LVM_TECH_VDO, BD_LVM_TECH_MODE_CREATE | BD_LVM_TECH_MODE_MODIFY, error);
4040 : }
4041 :
4042 : /**
4043 : * bd_lvm_vdolvpoolname:
4044 : * @vg_name: name of the VG containing the queried VDO LV
4045 : * @lv_name: name of the queried VDO LV
4046 : * @error: (out) (optional): place to store error (if any)
4047 : *
4048 : * Returns: (transfer full): the name of the pool volume for the @vg_name/@lv_name
4049 : * VDO LV or %NULL if failed to determine (@error) is set in those cases
4050 : *
4051 : * Tech category: %BD_LVM_TECH_VDO-%BD_LVM_TECH_MODE_QUERY
4052 : */
4053 2 : gchar* bd_lvm_vdolvpoolname (const gchar *vg_name, const gchar *lv_name, GError **error) {
4054 2 : GVariant *prop = NULL;
4055 2 : const gchar *segtype = NULL;
4056 2 : gchar *pool_obj_path = NULL;
4057 2 : gchar *ret = NULL;
4058 :
4059 2 : prop = get_lv_property (vg_name, lv_name, "SegType", error);
4060 2 : if (!prop)
4061 0 : return NULL;
4062 :
4063 2 : g_variant_get_child (prop, 0, "&s", &segtype);
4064 2 : if (g_strcmp0 (segtype, "vdo") != 0) {
4065 0 : g_variant_unref (prop);
4066 0 : g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_NOEXIST,
4067 : "The LV '%s' is not a VDO LV and thus have no VDO pool", lv_name);
4068 0 : return NULL;
4069 : }
4070 2 : g_variant_unref (prop);
4071 :
4072 2 : prop = get_lv_property (vg_name, lv_name, "PoolLv", error);
4073 2 : if (!prop)
4074 0 : return NULL;
4075 2 : g_variant_get (prop, "o", &pool_obj_path);
4076 2 : g_variant_unref (prop);
4077 :
4078 2 : prop = get_object_property (pool_obj_path, LV_CMN_INTF, "Name", error);
4079 2 : g_free (pool_obj_path);
4080 2 : if (!prop)
4081 0 : return NULL;
4082 2 : g_variant_get (prop, "s", &ret);
4083 2 : g_variant_unref (prop);
4084 :
4085 2 : return ret;
4086 : }
4087 :
4088 :
4089 :
4090 :
4091 :
4092 :
4093 :
4094 :
4095 :
4096 :
4097 :
4098 :
4099 :
|