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