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