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