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