]>
Commit | Line | Data |
---|---|---|
cc73685d | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
9be53773 | 2 | |
d38dd64a CB |
3 | #ifndef _GNU_SOURCE |
4 | #define _GNU_SOURCE 1 | |
5 | #endif | |
38683db4 | 6 | #include <dirent.h> |
9be53773 | 7 | #include <errno.h> |
38683db4 CB |
8 | #include <fcntl.h> |
9 | #include <grp.h> | |
10 | #include <inttypes.h> | |
9be53773 | 11 | #include <libgen.h> |
38683db4 CB |
12 | #include <sched.h> |
13 | #include <stdint.h> | |
14 | #include <stdio.h> | |
15 | #include <string.h> | |
38683db4 | 16 | #include <sys/mount.h> |
76a26f55 | 17 | #include <sys/prctl.h> |
38683db4 | 18 | #include <sys/stat.h> |
d38dd64a | 19 | #include <sys/types.h> |
38683db4 | 20 | #include <sys/wait.h> |
d38dd64a | 21 | #include <unistd.h> |
f2363e38 | 22 | |
28d832c4 | 23 | #include "btrfs.h" |
9be53773 | 24 | #include "conf.h" |
3188197d | 25 | #include "config.h" |
28d832c4 | 26 | #include "dir.h" |
9be53773 | 27 | #include "error.h" |
38683db4 | 28 | #include "log.h" |
28d832c4 CB |
29 | #include "loop.h" |
30 | #include "lvm.h" | |
38683db4 | 31 | #include "lxc.h" |
e9df7e1a | 32 | #include "lxclock.h" |
643c9ec9 | 33 | #include "memory_utils.h" |
38683db4 | 34 | #include "namespace.h" |
d38dd64a | 35 | #include "nbd.h" |
28d832c4 | 36 | #include "overlay.h" |
38683db4 | 37 | #include "parse.h" |
28d832c4 CB |
38 | #include "rbd.h" |
39 | #include "rsync.h" | |
40 | #include "storage.h" | |
f2d5a09d | 41 | #include "storage_utils.h" |
38683db4 | 42 | #include "utils.h" |
28d832c4 | 43 | #include "zfs.h" |
9be53773 | 44 | |
43f984ea DJ |
45 | #ifndef HAVE_STRLCPY |
46 | #include "include/strlcpy.h" | |
47 | #endif | |
48 | ||
bff13ba2 | 49 | #ifndef BLKGETSIZE64 |
eab15c1e | 50 | #define BLKGETSIZE64 _IOR(0x12, 114, size_t) |
bff13ba2 SG |
51 | #endif |
52 | ||
28d832c4 | 53 | lxc_log_define(storage, lxc); |
9be53773 | 54 | |
2b9cbd53 | 55 | /* btrfs */ |
10bc1861 | 56 | static const struct lxc_storage_ops btrfs_ops = { |
493de765 CB |
57 | .detect = &btrfs_detect, |
58 | .mount = &btrfs_mount, | |
59 | .umount = &btrfs_umount, | |
60 | .clone_paths = &btrfs_clonepaths, | |
61 | .destroy = &btrfs_destroy, | |
62 | .create = &btrfs_create, | |
3ef1df7c CB |
63 | .copy = &btrfs_create_clone, |
64 | .snapshot = &btrfs_create_snapshot, | |
493de765 CB |
65 | .can_snapshot = true, |
66 | .can_backup = true, | |
2b9cbd53 CB |
67 | }; |
68 | ||
304b4cf3 | 69 | /* dir */ |
10bc1861 | 70 | static const struct lxc_storage_ops dir_ops = { |
493de765 CB |
71 | .detect = &dir_detect, |
72 | .mount = &dir_mount, | |
73 | .umount = &dir_umount, | |
74 | .clone_paths = &dir_clonepaths, | |
75 | .destroy = &dir_destroy, | |
76 | .create = &dir_create, | |
3ef1df7c CB |
77 | .copy = NULL, |
78 | .snapshot = NULL, | |
493de765 CB |
79 | .can_snapshot = false, |
80 | .can_backup = true, | |
9d983015 CB |
81 | }; |
82 | ||
304b4cf3 | 83 | /* loop */ |
10bc1861 | 84 | static const struct lxc_storage_ops loop_ops = { |
493de765 CB |
85 | .detect = &loop_detect, |
86 | .mount = &loop_mount, | |
87 | .umount = &loop_umount, | |
88 | .clone_paths = &loop_clonepaths, | |
89 | .destroy = &loop_destroy, | |
90 | .create = &loop_create, | |
3ef1df7c CB |
91 | .copy = NULL, |
92 | .snapshot = NULL, | |
493de765 CB |
93 | .can_snapshot = false, |
94 | .can_backup = true, | |
304b4cf3 CB |
95 | }; |
96 | ||
2b9cbd53 | 97 | /* lvm */ |
10bc1861 | 98 | static const struct lxc_storage_ops lvm_ops = { |
493de765 CB |
99 | .detect = &lvm_detect, |
100 | .mount = &lvm_mount, | |
101 | .umount = &lvm_umount, | |
102 | .clone_paths = &lvm_clonepaths, | |
103 | .destroy = &lvm_destroy, | |
104 | .create = &lvm_create, | |
3ef1df7c CB |
105 | .copy = &lvm_create_clone, |
106 | .snapshot = &lvm_create_snapshot, | |
493de765 CB |
107 | .can_snapshot = true, |
108 | .can_backup = false, | |
2b9cbd53 CB |
109 | }; |
110 | ||
bf76c012 | 111 | /* nbd */ |
59eac805 | 112 | static const struct lxc_storage_ops nbd_ops = { |
493de765 CB |
113 | .detect = &nbd_detect, |
114 | .mount = &nbd_mount, | |
115 | .umount = &nbd_umount, | |
116 | .clone_paths = &nbd_clonepaths, | |
117 | .destroy = &nbd_destroy, | |
118 | .create = &nbd_create, | |
3ef1df7c CB |
119 | .copy = NULL, |
120 | .snapshot = NULL, | |
493de765 CB |
121 | .can_snapshot = true, |
122 | .can_backup = false, | |
bf76c012 CB |
123 | }; |
124 | ||
2b9cbd53 | 125 | /* overlay */ |
10bc1861 | 126 | static const struct lxc_storage_ops ovl_ops = { |
493de765 CB |
127 | .detect = &ovl_detect, |
128 | .mount = &ovl_mount, | |
129 | .umount = &ovl_umount, | |
130 | .clone_paths = &ovl_clonepaths, | |
131 | .destroy = &ovl_destroy, | |
132 | .create = &ovl_create, | |
3ef1df7c CB |
133 | .copy = NULL, |
134 | .snapshot = NULL, | |
493de765 CB |
135 | .can_snapshot = true, |
136 | .can_backup = true, | |
2b9cbd53 CB |
137 | }; |
138 | ||
3ceb2820 | 139 | /* rbd */ |
10bc1861 | 140 | static const struct lxc_storage_ops rbd_ops = { |
493de765 CB |
141 | .detect = &rbd_detect, |
142 | .mount = &rbd_mount, | |
143 | .umount = &rbd_umount, | |
144 | .clone_paths = &rbd_clonepaths, | |
145 | .destroy = &rbd_destroy, | |
146 | .create = &rbd_create, | |
3ef1df7c CB |
147 | .copy = NULL, |
148 | .snapshot = NULL, | |
493de765 CB |
149 | .can_snapshot = false, |
150 | .can_backup = false, | |
3ceb2820 CB |
151 | }; |
152 | ||
2b9cbd53 | 153 | /* zfs */ |
10bc1861 | 154 | static const struct lxc_storage_ops zfs_ops = { |
493de765 CB |
155 | .detect = &zfs_detect, |
156 | .mount = &zfs_mount, | |
157 | .umount = &zfs_umount, | |
158 | .clone_paths = &zfs_clonepaths, | |
159 | .destroy = &zfs_destroy, | |
160 | .create = &zfs_create, | |
3ef1df7c CB |
161 | .copy = &zfs_copy, |
162 | .snapshot = &zfs_snapshot, | |
493de765 CB |
163 | .can_snapshot = true, |
164 | .can_backup = true, | |
2b9cbd53 CB |
165 | }; |
166 | ||
10bc1861 | 167 | struct lxc_storage_type { |
cdb4e53a | 168 | const char *name; |
10bc1861 | 169 | const struct lxc_storage_ops *ops; |
cdb4e53a CB |
170 | }; |
171 | ||
10bc1861 | 172 | static const struct lxc_storage_type bdevs[] = { |
f7ac4459 | 173 | { .name = "dir", .ops = &dir_ops, }, |
493de765 CB |
174 | { .name = "zfs", .ops = &zfs_ops, }, |
175 | { .name = "lvm", .ops = &lvm_ops, }, | |
176 | { .name = "rbd", .ops = &rbd_ops, }, | |
177 | { .name = "btrfs", .ops = &btrfs_ops, }, | |
ba115175 | 178 | { .name = "overlay", .ops = &ovl_ops, }, |
493de765 CB |
179 | { .name = "overlayfs", .ops = &ovl_ops, }, |
180 | { .name = "loop", .ops = &loop_ops, }, | |
181 | { .name = "nbd", .ops = &nbd_ops, }, | |
cdb4e53a CB |
182 | }; |
183 | ||
10bc1861 | 184 | static const size_t numbdevs = sizeof(bdevs) / sizeof(struct lxc_storage_type); |
cdb4e53a | 185 | |
8a388ed4 | 186 | static const struct lxc_storage_type *get_storage_by_name(const char *path, |
63c9ffa0 | 187 | const char *type) |
38683db4 | 188 | { |
63c9ffa0 | 189 | int ret; |
f2d5a09d | 190 | size_t i, cmplen; |
38683db4 | 191 | |
63c9ffa0 CB |
192 | if (type) |
193 | cmplen = strlen(type); | |
194 | else | |
8a388ed4 | 195 | cmplen = strcspn(path, ":"); |
f2d5a09d | 196 | if (cmplen == 0) |
38683db4 CB |
197 | return NULL; |
198 | ||
63c9ffa0 CB |
199 | for (i = 0; i < numbdevs; i++) { |
200 | if (type) | |
201 | ret = strncmp(bdevs[i].name, type, cmplen); | |
202 | else | |
8a388ed4 | 203 | ret = strncmp(bdevs[i].name, path, cmplen); |
63c9ffa0 | 204 | if (ret == 0) |
f2d5a09d | 205 | break; |
63c9ffa0 | 206 | } |
38683db4 | 207 | |
f2d5a09d CB |
208 | if (i == numbdevs) |
209 | return NULL; | |
210 | ||
211 | DEBUG("Detected rootfs type \"%s\"", bdevs[i].name); | |
212 | return &bdevs[i]; | |
38683db4 CB |
213 | } |
214 | ||
8a388ed4 | 215 | static const struct lxc_storage_type *storage_query(struct lxc_conf *conf) |
9be53773 | 216 | { |
f2d5a09d | 217 | size_t i; |
10bc1861 | 218 | const struct lxc_storage_type *bdev; |
8a388ed4 CB |
219 | const char *path = conf->rootfs.path; |
220 | const char *type = conf->rootfs.bdev_type; | |
eddaaafd | 221 | |
8a388ed4 | 222 | bdev = get_storage_by_name(path, type); |
f2d5a09d CB |
223 | if (bdev) |
224 | return bdev; | |
493de765 | 225 | |
f2d5a09d | 226 | for (i = 0; i < numbdevs; i++) |
8a388ed4 | 227 | if (bdevs[i].ops->detect(path)) |
f2d5a09d | 228 | break; |
493de765 | 229 | |
f2d5a09d CB |
230 | if (i == numbdevs) |
231 | return NULL; | |
493de765 | 232 | |
f2d5a09d CB |
233 | DEBUG("Detected rootfs type \"%s\"", bdevs[i].name); |
234 | return &bdevs[i]; | |
235 | } | |
236 | ||
59eac805 | 237 | static struct lxc_storage *storage_get(const char *type) |
f2d5a09d CB |
238 | { |
239 | size_t i; | |
10bc1861 | 240 | struct lxc_storage *bdev; |
f2d5a09d | 241 | |
09f6f8c4 | 242 | for (i = 0; i < numbdevs; i++) |
f2d5a09d CB |
243 | if (strcmp(bdevs[i].name, type) == 0) |
244 | break; | |
f2d5a09d CB |
245 | |
246 | if (i == numbdevs) | |
247 | return NULL; | |
248 | ||
10bc1861 | 249 | bdev = malloc(sizeof(struct lxc_storage)); |
f2d5a09d CB |
250 | if (!bdev) |
251 | return NULL; | |
252 | ||
10bc1861 | 253 | memset(bdev, 0, sizeof(struct lxc_storage)); |
f2d5a09d CB |
254 | bdev->ops = bdevs[i].ops; |
255 | bdev->type = bdevs[i].name; | |
256 | ||
257 | return bdev; | |
258 | } | |
259 | ||
10bc1861 CB |
260 | static struct lxc_storage *do_storage_create(const char *dest, const char *type, |
261 | const char *cname, | |
facdf925 CB |
262 | struct bdev_specs *specs, |
263 | const struct lxc_conf *conf) | |
f2d5a09d | 264 | { |
09f6f8c4 | 265 | int ret; |
10bc1861 | 266 | struct lxc_storage *bdev; |
f2d5a09d | 267 | |
5e78e16a CB |
268 | if (!type) |
269 | type = "dir"; | |
270 | ||
10bc1861 | 271 | bdev = storage_get(type); |
f2d5a09d CB |
272 | if (!bdev) |
273 | return NULL; | |
493de765 | 274 | |
facdf925 | 275 | ret = bdev->ops->create(bdev, dest, cname, specs, conf); |
09f6f8c4 | 276 | if (ret < 0) { |
10bc1861 | 277 | storage_put(bdev); |
f2d5a09d CB |
278 | return NULL; |
279 | } | |
280 | ||
281 | return bdev; | |
cdb4e53a | 282 | } |
9be53773 | 283 | |
10bc1861 | 284 | bool storage_can_backup(struct lxc_conf *conf) |
cdb4e53a | 285 | { |
cdb4e53a | 286 | bool ret; |
8a388ed4 | 287 | struct lxc_storage *bdev; |
d659597e | 288 | |
8a388ed4 | 289 | bdev = storage_init(conf); |
cdb4e53a CB |
290 | if (!bdev) |
291 | return false; | |
493de765 | 292 | |
cdb4e53a | 293 | ret = bdev->ops->can_backup; |
10bc1861 | 294 | storage_put(bdev); |
9be53773 SH |
295 | return ret; |
296 | } | |
297 | ||
bf86c00a | 298 | /* If we're not snapshotting, then storage_copy becomes a simple case of mount |
cdb4e53a | 299 | * the original, mount the new, and rsync the contents. |
9be53773 | 300 | */ |
07db51a2 | 301 | struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname, |
10bc1861 CB |
302 | const char *lxcpath, const char *bdevtype, |
303 | int flags, const char *bdevdata, | |
07db51a2 | 304 | uint64_t newsize, bool *needs_rdep) |
9be53773 | 305 | { |
cdb4e53a | 306 | int ret; |
41dc7155 | 307 | const char *src_no_prefix; |
06d0056c CB |
308 | struct lxc_storage *new, *orig; |
309 | bool snap = (flags & LXC_CLONE_SNAPSHOT); | |
310 | bool maybe_snap = (flags & LXC_CLONE_MAYBE_SNAPSHOT); | |
311 | bool keepbdevtype = (flags & LXC_CLONE_KEEPBDEVTYPE); | |
07db51a2 CB |
312 | const char *src = c->lxc_conf->rootfs.path; |
313 | const char *oldname = c->name; | |
314 | const char *oldpath = c->config_path; | |
339de297 | 315 | char cmd_output[PATH_MAX] = {0}; |
06d0056c | 316 | struct rsync_data data = {0}; |
4e86cad3 CB |
317 | struct lxc_rootfs new_rootfs = { |
318 | .managed = true, | |
319 | .dfd_mnt = -EBADF, | |
320 | .dfd_dev = -EBADF, | |
321 | .dfd_host = -EBADF, | |
322 | .fd_path_pin = -EBADF, | |
323 | .dfd_idmapped = -EBADF, | |
4e86cad3 | 324 | }; |
9be53773 | 325 | |
45b4bb96 CB |
326 | if (!src) { |
327 | ERROR("No rootfs specified"); | |
328 | return NULL; | |
329 | } | |
330 | ||
6f748a97 CB |
331 | /* If the container name doesn't show up in the rootfs path, then we |
332 | * don't know how to come up with a new name. | |
cdb4e53a | 333 | */ |
3324c255 | 334 | if (!strstr(src, oldname)) { |
6f748a97 CB |
335 | ERROR("Original rootfs path \"%s\" does not include container " |
336 | "name \"%s\"", src, oldname); | |
cdb4e53a CB |
337 | return NULL; |
338 | } | |
9be53773 | 339 | |
4e86cad3 CB |
340 | ret = lxc_storage_prepare(c->lxc_conf); |
341 | if (ret) { | |
06d0056c | 342 | ERROR("Failed to detect storage driver for \"%s\"", oldname); |
cdb4e53a CB |
343 | return NULL; |
344 | } | |
4e86cad3 CB |
345 | orig = c->lxc_conf->rootfs.storage; |
346 | ||
347 | if (c->lxc_conf->rootfs.dfd_idmapped >= 0) { | |
2570cdf3 | 348 | new_rootfs.dfd_idmapped = dup_cloexec(c->lxc_conf->rootfs.dfd_idmapped); |
4e86cad3 CB |
349 | if (new_rootfs.dfd_idmapped < 0) { |
350 | SYSERROR("Failed to duplicate user namespace file descriptor"); | |
351 | lxc_storage_put(c->lxc_conf); | |
352 | return NULL; | |
353 | } | |
354 | } | |
9be53773 | 355 | |
cdb4e53a | 356 | if (!orig->dest) { |
cdb4e53a CB |
357 | size_t len; |
358 | struct stat sb; | |
9be53773 | 359 | |
cdb4e53a CB |
360 | len = strlen(oldpath) + strlen(oldname) + strlen("/rootfs") + 2; |
361 | orig->dest = malloc(len); | |
362 | if (!orig->dest) { | |
3324c255 | 363 | ERROR("Failed to allocate memory"); |
07db51a2 | 364 | goto on_error_put_orig; |
cdb4e53a | 365 | } |
493de765 | 366 | |
cdb4e53a CB |
367 | ret = snprintf(orig->dest, len, "%s/%s/rootfs", oldpath, oldname); |
368 | if (ret < 0 || (size_t)ret >= len) { | |
3324c255 | 369 | ERROR("Failed to create string"); |
07db51a2 | 370 | goto on_error_put_orig; |
cdb4e53a | 371 | } |
493de765 | 372 | |
6f748a97 CB |
373 | ret = stat(orig->dest, &sb); |
374 | if (ret < 0 && errno == ENOENT) { | |
375 | ret = mkdir_p(orig->dest, 0755); | |
376 | if (ret < 0) | |
eee1a9d7 | 377 | WARN("Failed to create directory \"%s\"", orig->dest); |
6f748a97 | 378 | } |
cdb4e53a | 379 | } |
9be53773 | 380 | |
3324c255 CB |
381 | /* Special case for snapshot. If the caller requested maybe_snapshot and |
382 | * keepbdevtype and the backing store is directory, then proceed with a | |
383 | * a copy clone rather than returning error. | |
cdb4e53a CB |
384 | */ |
385 | if (maybe_snap && keepbdevtype && !bdevtype && !orig->ops->can_snapshot) | |
386 | snap = false; | |
387 | ||
6f748a97 | 388 | /* If newtype is NULL and snapshot is set, then use overlay. */ |
70e95c8d | 389 | if (!bdevtype && !keepbdevtype && snap && !strcmp(orig->type, "dir")) |
ba115175 | 390 | bdevtype = "overlay"; |
cdb4e53a | 391 | |
e0010464 | 392 | if (am_guest_unpriv() && !unpriv_snap_allowed(orig, bdevtype, snap, maybe_snap)) { |
ba115175 CB |
393 | ERROR("Unsupported snapshot type \"%s\" for unprivileged users", |
394 | bdevtype ? bdevtype : "(null)"); | |
07db51a2 | 395 | goto on_error_put_orig; |
a17b1e65 SG |
396 | } |
397 | ||
07db51a2 | 398 | *needs_rdep = false; |
70e95c8d CB |
399 | if (bdevtype) { |
400 | if (snap && !strcmp(orig->type, "lvm") && | |
401 | !lvm_is_thin_volume(orig->src)) | |
402 | *needs_rdep = true; | |
403 | else if (!strcmp(bdevtype, "overlay") || | |
404 | !strcmp(bdevtype, "overlayfs")) | |
405 | *needs_rdep = true; | |
406 | } else { | |
407 | if (!snap && strcmp(oldpath, lxcpath)) | |
408 | bdevtype = "dir"; | |
409 | else | |
410 | bdevtype = orig->type; | |
9be53773 | 411 | |
70e95c8d CB |
412 | if (!strcmp(bdevtype, "overlay") || |
413 | !strcmp(bdevtype, "overlayfs")) | |
414 | *needs_rdep = true; | |
415 | } | |
b196516b CB |
416 | |
417 | /* get new bdev type */ | |
10bc1861 | 418 | new = storage_get(bdevtype); |
cdb4e53a | 419 | if (!new) { |
06d0056c | 420 | ERROR("Failed to initialize %s storage driver", |
493de765 | 421 | bdevtype ? bdevtype : orig->type); |
07db51a2 | 422 | goto on_error_put_orig; |
cdb4e53a | 423 | } |
06d0056c | 424 | TRACE("Initialized %s storage driver", new->type); |
4e86cad3 | 425 | new->rootfs = &new_rootfs; |
a17b1e65 | 426 | |
b196516b | 427 | /* create new paths */ |
6f748a97 | 428 | ret = new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath, |
07db51a2 | 429 | snap, newsize, c->lxc_conf); |
6f748a97 CB |
430 | if (ret < 0) { |
431 | ERROR("Failed creating new paths for clone of \"%s\"", src); | |
07db51a2 | 432 | goto on_error_put_new; |
cdb4e53a | 433 | } |
9be53773 | 434 | |
70e95c8d CB |
435 | /* When we create an overlay snapshot of an overlay container in the |
436 | * snapshot directory under "<lxcpath>/<name>/snaps/" we don't need to | |
437 | * record a dependency. If we would restore would also fail. | |
438 | */ | |
06d0056c CB |
439 | if ((strcmp(new->type, "overlay") == 0 || |
440 | strcmp(new->type, "overlayfs") == 0) && | |
70e95c8d CB |
441 | ret == LXC_CLONE_SNAPSHOT) |
442 | *needs_rdep = false; | |
443 | ||
6f748a97 | 444 | /* btrfs */ |
b196516b | 445 | if (!strcmp(orig->type, "btrfs") && !strcmp(new->type, "btrfs")) { |
06d0056c CB |
446 | bool bret; |
447 | ||
b196516b | 448 | if (snap || btrfs_same_fs(orig->dest, new->dest) == 0) |
07db51a2 | 449 | bret = new->ops->snapshot(c->lxc_conf, orig, new, 0); |
b196516b | 450 | else |
07db51a2 | 451 | bret = new->ops->copy(c->lxc_conf, orig, new, 0); |
b196516b | 452 | if (!bret) |
07db51a2 CB |
453 | goto on_error_put_new; |
454 | ||
455 | goto on_success; | |
b196516b CB |
456 | } |
457 | ||
6f748a97 | 458 | /* lvm */ |
d91e13d8 | 459 | if (!strcmp(orig->type, "lvm") && !strcmp(new->type, "lvm")) { |
06d0056c CB |
460 | bool bret; |
461 | ||
d91e13d8 | 462 | if (snap) |
06d0056c | 463 | bret = new->ops->snapshot(c->lxc_conf, orig, new, newsize); |
d91e13d8 | 464 | else |
07db51a2 | 465 | bret = new->ops->copy(c->lxc_conf, orig, new, newsize); |
3ef1df7c | 466 | if (!bret) |
07db51a2 CB |
467 | goto on_error_put_new; |
468 | ||
469 | goto on_success; | |
3ef1df7c CB |
470 | } |
471 | ||
472 | /* zfs */ | |
473 | if (!strcmp(orig->type, "zfs") && !strcmp(new->type, "zfs")) { | |
06d0056c | 474 | bool bret; |
3ef1df7c CB |
475 | |
476 | if (snap) | |
06d0056c | 477 | bret = new->ops->snapshot(c->lxc_conf, orig, new, newsize); |
3ef1df7c | 478 | else |
07db51a2 | 479 | bret = new->ops->copy(c->lxc_conf, orig, new, newsize); |
d91e13d8 | 480 | if (!bret) |
07db51a2 CB |
481 | goto on_error_put_new; |
482 | ||
483 | goto on_success; | |
d91e13d8 CB |
484 | } |
485 | ||
7a9e0f35 | 486 | if (strcmp(bdevtype, "btrfs")) { |
6f748a97 | 487 | if (!strcmp(new->type, "overlay") || !strcmp(new->type, "overlayfs")) |
7a9e0f35 CB |
488 | src_no_prefix = ovl_get_lower(new->src); |
489 | else | |
490 | src_no_prefix = lxc_storage_get_path(new->src, new->type); | |
491 | ||
e0010464 | 492 | if (am_guest_unpriv()) { |
07db51a2 | 493 | ret = chown_mapped_root(src_no_prefix, c->lxc_conf); |
6f748a97 CB |
494 | if (ret < 0) |
495 | WARN("Failed to chown \"%s\"", new->src); | |
496 | } | |
7a9e0f35 | 497 | } |
9be53773 | 498 | |
cdb4e53a | 499 | if (snap) |
07db51a2 | 500 | goto on_success; |
9be53773 | 501 | |
6f748a97 | 502 | /* rsync the contents from source to target */ |
db3ac7ba CB |
503 | data.orig = orig; |
504 | data.new = new; | |
e0010464 | 505 | if (am_guest_unpriv()) |
5c05427a CB |
506 | ret = userns_exec_full(c->lxc_conf, |
507 | lxc_storage_rsync_exec_wrapper, &data, | |
508 | "lxc_storage_rsync_exec_wrapper"); | |
07db51a2 | 509 | else |
db3ac7ba | 510 | ret = run_command(cmd_output, sizeof(cmd_output), |
17a367d8 | 511 | lxc_storage_rsync_exec_wrapper, (void *)&data); |
07db51a2 CB |
512 | if (ret < 0) { |
513 | ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", orig->dest, | |
514 | new->dest, | |
515 | cmd_output[0] != '\0' ? ": " : "", | |
516 | cmd_output[0] != '\0' ? cmd_output : ""); | |
517 | goto on_error_put_new; | |
9be53773 SH |
518 | } |
519 | ||
07db51a2 | 520 | on_success: |
4e86cad3 | 521 | lxc_storage_put(c->lxc_conf); |
07db51a2 | 522 | |
db3ac7ba | 523 | return new; |
cdb4e53a | 524 | |
07db51a2 | 525 | on_error_put_new: |
10bc1861 | 526 | storage_put(new); |
07db51a2 CB |
527 | |
528 | on_error_put_orig: | |
4e86cad3 | 529 | lxc_storage_put(c->lxc_conf); |
07db51a2 | 530 | |
cdb4e53a CB |
531 | return NULL; |
532 | } | |
533 | ||
10bc1861 | 534 | /* Create a backing store for a container. |
cdb4e53a CB |
535 | * If successful, return a struct bdev *, with the bdev mounted and ready |
536 | * for use. Before completing, the caller will need to call the | |
10bc1861 | 537 | * umount operation and storage_put(). |
cdb4e53a CB |
538 | * @dest: the mountpoint (i.e. /var/lib/lxc/$name/rootfs) |
539 | * @type: the bdevtype (dir, btrfs, zfs, rbd, etc) | |
540 | * @cname: the container name | |
541 | * @specs: details about the backing store to create, like fstype | |
542 | */ | |
10bc1861 | 543 | struct lxc_storage *storage_create(const char *dest, const char *type, |
facdf925 CB |
544 | const char *cname, struct bdev_specs *specs, |
545 | const struct lxc_conf *conf) | |
9be53773 | 546 | { |
e9e29a33 | 547 | int ret; |
10bc1861 | 548 | struct lxc_storage *bdev; |
cdb4e53a | 549 | char *best_options[] = {"btrfs", "zfs", "lvm", "dir", "rbd", NULL}; |
9be53773 | 550 | |
cdb4e53a | 551 | if (!type) |
facdf925 | 552 | return do_storage_create(dest, "dir", cname, specs, conf); |
cdb4e53a | 553 | |
e9e29a33 CB |
554 | ret = strcmp(type, "best"); |
555 | if (ret == 0) { | |
cdb4e53a | 556 | int i; |
10bc1861 CB |
557 | /* Try for the best backing store type, according to our |
558 | * opinionated preferences. | |
559 | */ | |
cdb4e53a | 560 | for (i = 0; best_options[i]; i++) { |
facdf925 | 561 | bdev = do_storage_create(dest, best_options[i], cname, specs, conf); |
10bc1861 | 562 | if (bdev) |
cdb4e53a CB |
563 | return bdev; |
564 | } | |
493de765 | 565 | |
10bc1861 | 566 | return NULL; |
9be53773 | 567 | } |
9be53773 | 568 | |
10bc1861 | 569 | /* -B lvm,dir */ |
e9e29a33 | 570 | if (strchr(type, ',')) { |
63fce0c1 | 571 | __do_free char *dup = NULL; |
643c9ec9 | 572 | char *token; |
43f984ea | 573 | |
643c9ec9 | 574 | dup = must_copy_string(type); |
eb29852f | 575 | lxc_iterate_parts(token, dup, ",") { |
facdf925 | 576 | bdev = do_storage_create(dest, token, cname, specs, conf); |
e9e29a33 | 577 | if (bdev) |
cdb4e53a CB |
578 | return bdev; |
579 | } | |
580 | } | |
581 | ||
facdf925 | 582 | return do_storage_create(dest, type, cname, specs, conf); |
9be53773 SH |
583 | } |
584 | ||
10bc1861 | 585 | bool storage_destroy(struct lxc_conf *conf) |
9be53773 | 586 | { |
10bc1861 | 587 | struct lxc_storage *r; |
cdb4e53a | 588 | bool ret = false; |
ed05aac8 | 589 | int destroy_rv = 0; |
9be53773 | 590 | |
8a388ed4 | 591 | r = storage_init(conf); |
cdb4e53a CB |
592 | if (!r) |
593 | return ret; | |
594 | ||
ed05aac8 MM |
595 | destroy_rv = r->ops->destroy(r); |
596 | if (destroy_rv == 0) | |
cdb4e53a | 597 | ret = true; |
cdb4e53a | 598 | |
10bc1861 | 599 | storage_put(r); |
cdb4e53a CB |
600 | return ret; |
601 | } | |
602 | ||
8a388ed4 | 603 | struct lxc_storage *storage_init(struct lxc_conf *conf) |
cdb4e53a | 604 | { |
10bc1861 CB |
605 | struct lxc_storage *bdev; |
606 | const struct lxc_storage_type *q; | |
8a388ed4 CB |
607 | const char *src = conf->rootfs.path; |
608 | const char *dst = conf->rootfs.mount; | |
e73af35b | 609 | const char *mntopts = conf->rootfs.mnt_opts.raw_options; |
cdb4e53a | 610 | |
17a367d8 CB |
611 | BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS); |
612 | ||
cdb4e53a | 613 | if (!src) |
9be53773 | 614 | return NULL; |
cdb4e53a | 615 | |
8a388ed4 | 616 | q = storage_query(conf); |
cdb4e53a | 617 | if (!q) |
9be53773 | 618 | return NULL; |
cdb4e53a | 619 | |
79defd88 | 620 | bdev = zalloc(sizeof(struct lxc_storage)); |
cdb4e53a | 621 | if (!bdev) |
9be53773 | 622 | return NULL; |
493de765 | 623 | |
79defd88 CB |
624 | bdev->ops = q->ops; |
625 | bdev->type = q->name; | |
626 | bdev->rootfs = &conf->rootfs; | |
8a388ed4 | 627 | |
cdb4e53a CB |
628 | if (mntopts) |
629 | bdev->mntopts = strdup(mntopts); | |
8a388ed4 | 630 | |
cdb4e53a CB |
631 | if (src) |
632 | bdev->src = strdup(src); | |
8a388ed4 | 633 | |
cdb4e53a CB |
634 | if (dst) |
635 | bdev->dest = strdup(dst); | |
8a388ed4 | 636 | |
cdb4e53a CB |
637 | if (strcmp(bdev->type, "nbd") == 0) |
638 | bdev->nbd_idx = conf->nbd_idx; | |
639 | ||
640 | return bdev; | |
641 | } | |
642 | ||
068aa488 | 643 | bool storage_is_dir(struct lxc_conf *conf) |
cdb4e53a | 644 | { |
10bc1861 | 645 | struct lxc_storage *orig; |
068aa488 | 646 | char *type = conf->rootfs.bdev_type; |
10bc1861 CB |
647 | bool bret = false; |
648 | ||
068aa488 CB |
649 | if (type) |
650 | return (strcmp(type, "dir") == 0); | |
651 | ||
8a388ed4 | 652 | orig = storage_init(conf); |
cdb4e53a | 653 | if (!orig) |
10bc1861 CB |
654 | return bret; |
655 | ||
cdb4e53a | 656 | if (strcmp(orig->type, "dir") == 0) |
10bc1861 CB |
657 | bret = true; |
658 | ||
659 | storage_put(orig); | |
660 | return bret; | |
cdb4e53a CB |
661 | } |
662 | ||
10bc1861 | 663 | void storage_put(struct lxc_storage *bdev) |
cdb4e53a | 664 | { |
4e86cad3 CB |
665 | if (bdev) { |
666 | free_disarm(bdev->mntopts); | |
667 | free_disarm(bdev->src); | |
668 | free_disarm(bdev->dest); | |
669 | free_disarm(bdev); | |
670 | } | |
cdb4e53a CB |
671 | } |
672 | ||
cdb4e53a CB |
673 | bool rootfs_is_blockdev(struct lxc_conf *conf) |
674 | { | |
10bc1861 | 675 | const struct lxc_storage_type *q; |
cdb4e53a CB |
676 | struct stat st; |
677 | int ret; | |
678 | ||
679 | if (!conf->rootfs.path || strcmp(conf->rootfs.path, "/") == 0 || | |
493de765 | 680 | strlen(conf->rootfs.path) == 0) |
cdb4e53a CB |
681 | return false; |
682 | ||
683 | ret = stat(conf->rootfs.path, &st); | |
684 | if (ret == 0 && S_ISBLK(st.st_mode)) | |
685 | return true; | |
493de765 | 686 | |
8a388ed4 | 687 | q = storage_query(conf); |
cdb4e53a CB |
688 | if (!q) |
689 | return false; | |
493de765 | 690 | |
cdb4e53a | 691 | if (strcmp(q->name, "lvm") == 0 || |
493de765 | 692 | strcmp(q->name, "loop") == 0 || |
f83dd99e CB |
693 | strcmp(q->name, "nbd") == 0 || |
694 | strcmp(q->name, "rbd") == 0 || | |
695 | strcmp(q->name, "zfs") == 0) | |
cdb4e53a | 696 | return true; |
493de765 | 697 | |
cdb4e53a CB |
698 | return false; |
699 | } | |
4f25fd38 | 700 | |
41dc7155 | 701 | const char *lxc_storage_get_path(char *src, const char *prefix) |
4f25fd38 CB |
702 | { |
703 | size_t prefix_len; | |
704 | ||
705 | prefix_len = strlen(prefix); | |
706 | if (!strncmp(src, prefix, prefix_len) && (*(src + prefix_len) == ':')) | |
707 | return (src + prefix_len + 1); | |
708 | ||
709 | return src; | |
710 | } |