]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/storage/lvm.c
tree-wide: struct bdev -> struct lxc_storage
[mirror_lxc.git] / src / lxc / storage / lvm.c
CommitLineData
2b9cbd53
CB
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#define _GNU_SOURCE
d91e13d8
CB
25#define __STDC_FORMAT_MACROS
26#include <inttypes.h>
2b9cbd53
CB
27#include <stdint.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
ce831b3b 32#include <sys/sysmacros.h>
23c9c64d 33#include <sys/wait.h>
2b9cbd53 34
af6824fc 35#include "config.h"
2b9cbd53 36#include "log.h"
28d832c4
CB
37#include "lvm.h"
38#include "rsync.h"
39#include "storage.h"
f2d5a09d 40#include "storage_utils.h"
2b9cbd53
CB
41#include "utils.h"
42
af6824fc 43#ifdef MAJOR_IN_MKDEV
d91e13d8 44#include <sys/mkdev.h>
af6824fc 45#endif
af6824fc 46
10bc1861 47lxc_log_define(lvm, lxc);
2b9cbd53 48
d91e13d8
CB
49struct lvcreate_args {
50 const char *size;
51 const char *vg;
52 const char *lv;
53 const char *thinpool;
2b9cbd53 54
d91e13d8
CB
55 /* snapshot specific arguments */
56 const char *source_lv;
57};
58
59static int lvm_destroy_exec_wrapper(void *data)
60{
61 struct lvcreate_args *args = data;
62
63 (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
64 execlp("lvremove", "lvremove", "-f", args->lv, (char *)NULL);
65
66 return -1;
67}
68
69static int lvm_create_exec_wrapper(void *data)
70{
71 struct lvcreate_args *args = data;
72
73 (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
74 if (args->thinpool)
75 execlp("lvcreate", "lvcreate", "--thinpool", args->thinpool,
76 "-V", args->size, args->vg, "-n", args->lv,
77 (char *)NULL);
78 else
79 execlp("lvcreate", "lvcreate", "-L", args->size, args->vg, "-n",
80 args->lv, (char *)NULL);
81
82 return -1;
83}
84
85static int lvm_snapshot_exec_wrapper(void *data)
86{
87 struct lvcreate_args *args = data;
88
89 (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
90 if (args->thinpool)
91 execlp("lvcreate", "lvcreate", "-s", "-n", args->lv,
92 args->source_lv, (char *)NULL);
93 else
94 execlp("lvcreate", "lvcreate", "-s", "-L", args->size, "-n",
95 args->lv, args->source_lv, (char *)NULL);
96
97 return -1;
98}
99
100/* The path must be "/dev/<vg>/<lv>". The volume group <vg> must be an existing
101 * volume group, and the logical volume <lv> must not yet exist.
102 * This function will attempt to create "/dev/<vg>/<lv> of size <size>. If
02b5e381 103 * thinpool is specified, we'll check for it's existence and if it's a valid
d91e13d8
CB
104 * thin pool, and if so, we'll create the requested logical volume from that
105 * thin pool.
02b5e381
CB
106 */
107static int do_lvm_create(const char *path, uint64_t size, const char *thinpool)
2b9cbd53 108{
d91e13d8
CB
109 int len, ret;
110 char *pathdup, *vg, *lv;
111 char cmd_output[MAXPATHLEN];
112 char sz[24];
113 char *tp = NULL;
114 struct lvcreate_args cmd_args = {0};
2b9cbd53 115
d91e13d8
CB
116 ret = snprintf(sz, 24, "%" PRIu64 "b", size);
117 if (ret < 0 || ret >= 24) {
118 ERROR("Failed to create string: %d", ret);
2b9cbd53
CB
119 return -1;
120 }
2b9cbd53
CB
121
122 pathdup = strdup(path);
d91e13d8
CB
123 if (!pathdup) {
124 ERROR("Failed to duplicate string \"%s\"", path);
125 return -1;
126 }
2b9cbd53
CB
127
128 lv = strrchr(pathdup, '/');
d91e13d8
CB
129 if (!lv) {
130 ERROR("Failed to detect \"/\" in string \"%s\"", pathdup);
131 free(pathdup);
132 return -1;
133 }
2b9cbd53
CB
134 *lv = '\0';
135 lv++;
d91e13d8 136 TRACE("Parsed logical volume \"%s\"", lv);
2b9cbd53
CB
137
138 vg = strrchr(pathdup, '/');
d91e13d8
CB
139 if (!vg) {
140 ERROR("Failed to detect \"/\" in string \"%s\"", pathdup);
141 free(pathdup);
142 return -1;
143 }
2b9cbd53 144 vg++;
d91e13d8 145 TRACE("Parsed volume group \"%s\"", vg);
2b9cbd53
CB
146
147 if (thinpool) {
148 len = strlen(pathdup) + strlen(thinpool) + 2;
149 tp = alloca(len);
150
151 ret = snprintf(tp, len, "%s/%s", pathdup, thinpool);
d91e13d8
CB
152 if (ret < 0 || ret >= len) {
153 ERROR("Failed to create string: %d", ret);
154 free(pathdup);
155 return -1;
156 }
2b9cbd53
CB
157
158 ret = lvm_is_thin_pool(tp);
d91e13d8
CB
159 TRACE("got %d for thin pool at path: %s", ret, tp);
160 if (ret < 0) {
161 ERROR("Failed to detect whether \"%s\" is a thinpool", tp);
162 free(pathdup);
163 return -1;
164 } else if (!ret) {
165 TRACE("Detected that \"%s\" is not a thinpool", tp);
2b9cbd53 166 tp = NULL;
d91e13d8
CB
167 } else {
168 TRACE("Detected \"%s\" is a thinpool", tp);
169 }
2b9cbd53
CB
170 }
171
d91e13d8
CB
172 cmd_args.thinpool = tp;
173 cmd_args.vg = vg;
174 cmd_args.lv = lv;
175 cmd_args.size = sz;
176 TRACE("Creating new lvm storage volume \"%s\" on volume group \"%s\" "
177 "of size \"%s\"", lv, vg, sz);
178 ret = run_command(cmd_output, sizeof(cmd_output),
179 lvm_create_exec_wrapper, (void *)&cmd_args);
180 if (ret < 0) {
181 ERROR("Failed to create logical volume \"%s\": %s", lv,
182 cmd_output);
183 free(pathdup);
184 return -1;
185 }
186 TRACE("Created new lvm storage volume \"%s\" on volume group \"%s\" "
187 "of size \"%s\"", lv, vg, sz);
2b9cbd53 188
d91e13d8
CB
189 free(pathdup);
190 return ret;
2b9cbd53
CB
191}
192
d91e13d8
CB
193/* Look at "/sys/dev/block/maj:min/dm/uuid". If it contains the hardcoded LVM
194 * prefix "LVM-" then this is an lvm2 LV.
2b9cbd53 195 */
3d2ae1e2 196bool lvm_detect(const char *path)
2b9cbd53 197{
d91e13d8
CB
198 int fd;
199 ssize_t ret;
2b9cbd53 200 struct stat statbuf;
d91e13d8 201 char devp[MAXPATHLEN], buf[4];
2b9cbd53 202
f7ac4459 203 if (!strncmp(path, "lvm:", 4))
3d2ae1e2 204 return true;
2b9cbd53
CB
205
206 ret = stat(path, &statbuf);
d91e13d8 207 if (ret < 0)
3d2ae1e2 208 return false;
d91e13d8 209
2b9cbd53 210 if (!S_ISBLK(statbuf.st_mode))
3d2ae1e2 211 return false;
2b9cbd53
CB
212
213 ret = snprintf(devp, MAXPATHLEN, "/sys/dev/block/%d:%d/dm/uuid",
d91e13d8 214 major(statbuf.st_rdev), minor(statbuf.st_rdev));
2b9cbd53 215 if (ret < 0 || ret >= MAXPATHLEN) {
d91e13d8 216 ERROR("Failed to create string");
3d2ae1e2 217 return false;
2b9cbd53 218 }
d91e13d8
CB
219
220 fd = open(devp, O_RDONLY);
221 if (fd < 0)
3d2ae1e2 222 return false;
d91e13d8
CB
223
224 ret = read(fd, buf, sizeof(buf));
225 close(fd);
226 if (ret != sizeof(buf))
3d2ae1e2 227 return false;
d91e13d8
CB
228
229 if (strncmp(buf, "LVM-", 4))
3d2ae1e2 230 return false;
d91e13d8 231
3d2ae1e2 232 return true;
2b9cbd53
CB
233}
234
10bc1861 235int lvm_mount(struct lxc_storage *bdev)
2b9cbd53 236{
11274f69
CB
237 char *src;
238
2b9cbd53
CB
239 if (strcmp(bdev->type, "lvm"))
240 return -22;
11274f69 241
2b9cbd53
CB
242 if (!bdev->src || !bdev->dest)
243 return -22;
11274f69
CB
244
245 src = lxc_storage_get_path(bdev->src, bdev->type);
246
247 /* If we might pass in data sometime, then we'll have to enrich
248 * mount_unknown_fs().
249 */
250 return mount_unknown_fs(src, bdev->dest, bdev->mntopts);
2b9cbd53
CB
251}
252
10bc1861 253int lvm_umount(struct lxc_storage *bdev)
2b9cbd53
CB
254{
255 if (strcmp(bdev->type, "lvm"))
256 return -22;
11274f69 257
2b9cbd53
CB
258 if (!bdev->src || !bdev->dest)
259 return -22;
11274f69 260
2b9cbd53
CB
261 return umount(bdev->dest);
262}
263
264int lvm_compare_lv_attr(const char *path, int pos, const char expected)
265{
266 struct lxc_popen_FILE *f;
d91e13d8
CB
267 int ret, len, status;
268 char *cmd;
269 char output[12];
270 int start=0;
2b9cbd53
CB
271 const char *lvscmd = "lvs --unbuffered --noheadings -o lv_attr %s 2>/dev/null";
272
273 len = strlen(lvscmd) + strlen(path) - 1;
274 cmd = alloca(len);
275
276 ret = snprintf(cmd, len, lvscmd, path);
277 if (ret < 0 || ret >= len)
278 return -1;
279
280 f = lxc_popen(cmd);
d91e13d8 281 if (!f) {
2b9cbd53
CB
282 SYSERROR("popen failed");
283 return -1;
284 }
285
d91e13d8
CB
286 if (!fgets(output, 12, f->f))
287 ret = 1;
2b9cbd53
CB
288
289 status = lxc_pclose(f);
d91e13d8 290 /* Assume either vg or lvs do not exist, default comparison to false. */
2b9cbd53 291 if (ret || WEXITSTATUS(status))
2b9cbd53
CB
292 return 0;
293
294 len = strlen(output);
d91e13d8
CB
295 while (start < len && output[start] == ' ')
296 start++;
2b9cbd53
CB
297
298 if (start + pos < len && output[start + pos] == expected)
299 return 1;
300
301 return 0;
302}
303
304int lvm_is_thin_volume(const char *path)
305{
306 return lvm_compare_lv_attr(path, 6, 't');
307}
308
309int lvm_is_thin_pool(const char *path)
310{
311 return lvm_compare_lv_attr(path, 0, 't');
312}
313
314int lvm_snapshot(const char *orig, const char *path, uint64_t size)
315{
d91e13d8
CB
316 int ret;
317 char *pathdup, *lv;
318 char sz[24];
319 char cmd_output[MAXPATHLEN];
320 struct lvcreate_args cmd_args = {0};
2b9cbd53 321
d91e13d8
CB
322 ret = snprintf(sz, 24, "%" PRIu64 "b", size);
323 if (ret < 0 || ret >= 24) {
324 ERROR("Failed to create string");
2b9cbd53
CB
325 return -1;
326 }
2b9cbd53
CB
327
328 pathdup = strdup(path);
d91e13d8
CB
329 if (!pathdup) {
330 ERROR("Failed to duplicate string \"%s\"", path);
331 return -1;
332 }
333
2b9cbd53
CB
334 lv = strrchr(pathdup, '/');
335 if (!lv) {
d91e13d8 336 ERROR("Failed to detect \"/\" in string \"%s\"", pathdup);
2b9cbd53 337 free(pathdup);
d91e13d8 338 return -1;
2b9cbd53
CB
339 }
340 *lv = '\0';
341 lv++;
d91e13d8 342 TRACE("Parsed logical volume \"%s\"", lv);
2b9cbd53 343
d91e13d8
CB
344 /* Check if the original logical volume is backed by a thinpool, in
345 * which case we cannot specify a size that's different from the
346 * original size.
347 */
2b9cbd53 348 ret = lvm_is_thin_volume(orig);
d91e13d8 349 if (ret < 0) {
2b9cbd53
CB
350 free(pathdup);
351 return -1;
d91e13d8
CB
352 } else if (ret) {
353 cmd_args.thinpool = orig;
2b9cbd53
CB
354 }
355
d91e13d8
CB
356 cmd_args.lv = lv;
357 cmd_args.source_lv = orig;
358 cmd_args.size = sz;
359 TRACE("Creating new lvm snapshot \"%s\" of \"%s\" with size \"%s\"", lv,
360 orig, sz);
361 ret = run_command(cmd_output, sizeof(cmd_output),
362 lvm_snapshot_exec_wrapper, (void *)&cmd_args);
363 if (ret < 0) {
364 ERROR("Failed to create logical volume \"%s\": %s", orig,
365 cmd_output);
366 free(pathdup);
367 return -1;
2b9cbd53
CB
368 }
369
370 free(pathdup);
d91e13d8 371 return 0;
2b9cbd53
CB
372}
373
10bc1861
CB
374int lvm_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
375 const char *oldname, const char *cname, const char *oldpath,
376 const char *lxcpath, int snap, uint64_t newsize,
377 struct lxc_conf *conf)
2b9cbd53 378{
2b9cbd53 379 int len, ret;
d91e13d8 380 const char *vg;
2b9cbd53
CB
381
382 if (!orig->src || !orig->dest)
383 return -1;
384
d91e13d8
CB
385 if (strcmp(orig->type, "lvm") && snap) {
386 ERROR("LVM snapshot from \"%s\" storage driver is not supported",
387 orig->type);
388 return -1;
389 }
2b9cbd53 390
d91e13d8 391 if (strcmp(orig->type, "lvm")) {
2b9cbd53 392 vg = lxc_global_config_value("lxc.bdev.lvm.vg");
d91e13d8
CB
393 new->src = lxc_string_join(
394 "/",
395 (const char *[]){"lvm:", "dev", vg, cname, NULL},
396 false);
397 } else {
398 char *dup, *slider, *src;
01e5fa07 399
d91e13d8 400 src = lxc_storage_get_path(orig->src, orig->type);
11274f69 401
d91e13d8
CB
402 dup = strdup(src);
403 if (!dup) {
404 ERROR("Failed to duplicate string \"%s\"", src);
2b9cbd53 405 return -1;
d91e13d8
CB
406 }
407
408 slider = strrchr(dup, '/');
409 if (!slider) {
410 ERROR("Failed to detect \"/\" in string \"%s\"", dup);
411 free(dup);
2b9cbd53 412 return -1;
d91e13d8
CB
413 }
414 *slider = '\0';
415 slider = dup;
416
417 new->src = lxc_string_join(
418 "/",
419 (const char *[]){"lvm:", *slider == '/' ? ++slider : slider,
420 cname, NULL},
421 false);
422 free(dup);
423 }
424 if (!new->src) {
425 ERROR("Failed to create string");
426 return -1;
2b9cbd53
CB
427 }
428
429 if (orig->mntopts) {
430 new->mntopts = strdup(orig->mntopts);
d91e13d8
CB
431 if (!new->mntopts) {
432 ERROR("Failed to duplicate string \"%s\"", orig->mntopts);
2b9cbd53 433 return -1;
d91e13d8 434 }
2b9cbd53
CB
435 }
436
437 len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
438 new->dest = malloc(len);
d91e13d8
CB
439 if (!new->dest) {
440 ERROR("Failed to allocate memory");
2b9cbd53 441 return -1;
d91e13d8
CB
442 }
443
2b9cbd53 444 ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
d91e13d8
CB
445 if (ret < 0 || ret >= len) {
446 ERROR("Failed to create string");
2b9cbd53 447 return -1;
d91e13d8
CB
448 }
449
450 ret = mkdir_p(new->dest, 0755);
451 if (ret < 0) {
452 SYSERROR("Failed to create directory \"%s\"", new->dest);
2b9cbd53 453 return -1;
d91e13d8
CB
454 }
455
456 return 0;
457}
458
10bc1861
CB
459bool lvm_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
460 struct lxc_storage *new, uint64_t newsize)
d91e13d8
CB
461{
462 char *src;
463 const char *thinpool;
464 int ret;
465 struct rsync_data data;
466 char *cmd_args[2];
467 char cmd_output[MAXPATHLEN];
468 char fstype[100] = "ext4";
469 uint64_t size = newsize;
2b9cbd53
CB
470
471 if (is_blktype(orig)) {
d91e13d8 472 /* detect size */
2b9cbd53 473 if (!newsize && blk_getsize(orig, &size) < 0) {
d91e13d8
CB
474 ERROR("Failed to detect size of logical volume \"%s\"",
475 orig->src);
2b9cbd53
CB
476 return -1;
477 }
d91e13d8
CB
478
479 /* detect filesystem */
2b9cbd53 480 if (detect_fs(orig, fstype, 100) < 0) {
d91e13d8 481 INFO("Failed to detect filesystem type for \"%s\"", orig->src);
2b9cbd53
CB
482 return -1;
483 }
d91e13d8 484 } else if (!newsize) {
2b9cbd53
CB
485 size = DEFAULT_FS_SIZE;
486 }
487
d91e13d8
CB
488 src = lxc_storage_get_path(new->src, "lvm");
489 thinpool = lxc_global_config_value("lxc.bdev.lvm.thin_pool");
11274f69 490
d91e13d8
CB
491 ret = do_lvm_create(src, size, thinpool);
492 if (ret < 0) {
493 ERROR("Failed to create lvm storage volume \"%s\"", src);
494 return -1;
495 }
11274f69 496
d91e13d8
CB
497 cmd_args[0] = fstype;
498 cmd_args[1] = src;
499 ret = run_command(cmd_output, sizeof(cmd_output),
500 do_mkfs_exec_wrapper, (void *)cmd_args);
501 if (ret < 0) {
502 ERROR("Failed to create new filesystem \"%s\" for lvm storage "
503 "volume \"%s\": %s", fstype, src, cmd_output);
504 return -1;
505 }
506
507 data.orig = orig;
508 data.new = new;
509 ret = rsync_rootfs(&data);
510 if (ret < 0) {
511 ERROR("Failed to rsync from \"%s\" to \"%s\"", orig->dest,
512 new->dest);
513 return false;
514 }
515
516 TRACE("Created lvm storage volume \"%s\"", new->dest);
517 return true;
518}
11274f69 519
10bc1861
CB
520bool lvm_create_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
521 struct lxc_storage *new, uint64_t newsize)
d91e13d8
CB
522{
523 int ret;
524 char *newsrc, *origsrc;
525 uint64_t size = newsize;
526
527 if (is_blktype(orig)) {
528 if (!newsize && blk_getsize(orig, &size) < 0) {
529 ERROR("Failed to detect size of logical volume \"%s\"",
530 orig->src);
2b9cbd53
CB
531 return -1;
532 }
d91e13d8
CB
533 } else if (!newsize) {
534 size = DEFAULT_FS_SIZE;
535 }
a5b18cb1 536
d91e13d8
CB
537 origsrc = lxc_storage_get_path(orig->src, "lvm");
538 newsrc = lxc_storage_get_path(new->src, "lvm");
539
540 ret = lvm_snapshot(origsrc, newsrc, size);
541 if (ret < 0) {
542 ERROR("Failed to create lvm \"%s\" snapshot of \"%s\"",
543 new->src, orig->src);
544 return false;
2b9cbd53
CB
545 }
546
d91e13d8
CB
547 TRACE("Created lvm snapshot \"%s\" from \"%s\"", new->dest, orig->dest);
548 return true;
2b9cbd53
CB
549}
550
10bc1861 551int lvm_destroy(struct lxc_storage *orig)
2b9cbd53 552{
d91e13d8
CB
553 int ret;
554 char cmd_output[MAXPATHLEN];
555 struct lvcreate_args cmd_args = {0};
556
557 cmd_args.lv = lxc_storage_get_path(orig->src, "lvm");
558 ret = run_command(cmd_output, sizeof(cmd_output),
559 lvm_destroy_exec_wrapper, (void *)&cmd_args);
560 if (ret < 0) {
561 ERROR("Failed to destroy logical volume \"%s\": %s", orig->src,
562 cmd_output);
2b9cbd53 563 return -1;
2b9cbd53 564 }
11274f69 565
d91e13d8
CB
566 TRACE("Destroyed logical volume \"%s\"", orig->src);
567 return 0;
2b9cbd53
CB
568}
569
10bc1861 570int lvm_create(struct lxc_storage *bdev, const char *dest, const char *n,
d91e13d8 571 struct bdev_specs *specs)
2b9cbd53
CB
572{
573 const char *vg, *thinpool, *fstype, *lv = n;
574 uint64_t sz;
575 int ret, len;
a5b18cb1
CB
576 const char *cmd_args[2];
577 char cmd_output[MAXPATHLEN];
2b9cbd53
CB
578
579 if (!specs)
580 return -1;
581
582 vg = specs->lvm.vg;
583 if (!vg)
584 vg = lxc_global_config_value("lxc.bdev.lvm.vg");
585
586 thinpool = specs->lvm.thinpool;
587 if (!thinpool)
588 thinpool = lxc_global_config_value("lxc.bdev.lvm.thin_pool");
589
590 /* /dev/$vg/$lv */
591 if (specs->lvm.lv)
592 lv = specs->lvm.lv;
593
11274f69 594 len = strlen(vg) + strlen(lv) + 4 + 7;
2b9cbd53 595 bdev->src = malloc(len);
d91e13d8
CB
596 if (!bdev->src) {
597 ERROR("Failed to allocate memory");
2b9cbd53 598 return -1;
d91e13d8 599 }
2b9cbd53 600
11274f69 601 ret = snprintf(bdev->src, len, "lvm:/dev/%s/%s", vg, lv);
d91e13d8
CB
602 if (ret < 0 || ret >= len) {
603 ERROR("Failed to create string");
2b9cbd53 604 return -1;
d91e13d8 605 }
2b9cbd53 606
d91e13d8 607 /* size is in bytes */
2b9cbd53
CB
608 sz = specs->fssize;
609 if (!sz)
610 sz = DEFAULT_FS_SIZE;
611
d91e13d8
CB
612 ret = do_lvm_create(bdev->src + 4, sz, thinpool);
613 if (ret < 0) {
614 ERROR("Error creating new logical volume \"%s\" of size "
615 "\"%" PRIu64 " bytes\"", bdev->src, sz);
2b9cbd53
CB
616 return -1;
617 }
618
619 fstype = specs->fstype;
620 if (!fstype)
621 fstype = DEFAULT_FSTYPE;
a5b18cb1
CB
622
623 cmd_args[0] = fstype;
d91e13d8 624 cmd_args[1] = lxc_storage_get_path(bdev->src, bdev->type);
a5b18cb1
CB
625 ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
626 (void *)cmd_args);
d91e13d8
CB
627 if (ret < 0) {
628 ERROR("Failed to create new logical volume \"%s\": %s",
629 bdev->src, cmd_output);
2b9cbd53 630 return -1;
d91e13d8 631 }
a5b18cb1 632
d91e13d8
CB
633 bdev->dest = strdup(dest);
634 if (!bdev->dest) {
635 ERROR("Failed to duplicate string \"%s\"", dest);
2b9cbd53 636 return -1;
d91e13d8 637 }
2b9cbd53 638
d91e13d8
CB
639 ret = mkdir_p(bdev->dest, 0755);
640 if (ret < 0) {
641 SYSERROR("Failed to create directory \"%s\"", bdev->dest);
2b9cbd53
CB
642 return -1;
643 }
644
d91e13d8 645 TRACE("Created new logical volume \"%s\"", bdev->dest);
2b9cbd53
CB
646 return 0;
647}