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