1 /* SPDX-License-Identifier: LGPL-2.1+ */
15 #include "lxccontainer.h"
17 #include "memory_utils.h"
21 #include "storage_utils.h"
24 lxc_log_define(overlay
, lxc
);
26 static char *ovl_name
;
27 static char *ovl_version
[] = {"overlay", "overlayfs"};
29 static char *ovl_detect_name(void);
30 static int ovl_do_rsync(const char *src
, const char *dest
,
31 struct lxc_conf
*conf
);
32 static int ovl_remount_on_enodev(const char *lower
, const char *target
,
33 const char *name
, unsigned long mountflags
,
36 int ovl_clonepaths(struct lxc_storage
*orig
, struct lxc_storage
*new, const char *oldname
,
37 const char *cname
, const char *oldpath
, const char *lxcpath
,
38 int snap
, uint64_t newsize
, struct lxc_conf
*conf
)
44 ERROR("The overlay storage driver can only be used for "
49 if (!orig
->src
|| !orig
->dest
)
52 new->dest
= must_make_path(lxcpath
, cname
, "rootfs", NULL
);
54 ret
= mkdir_p(new->dest
, 0755);
55 if (ret
< 0 && errno
!= EEXIST
) {
56 SYSERROR("Failed to create directory \"%s\"", new->dest
);
60 if (am_guest_unpriv()) {
61 ret
= chown_mapped_root(new->dest
, conf
);
63 WARN("Failed to update ownership of %s", new->dest
);
66 if (strcmp(orig
->type
, "dir") == 0) {
67 char *delta
, *lastslash
;
69 int len
, lastslashidx
;
71 /* If we have "/var/lib/lxc/c2/rootfs" then delta will be
72 * "/var/lib/lxc/c2/delta0".
74 lastslash
= strrchr(new->dest
, '/');
76 ERROR("Failed to detect \"/\" in string \"%s\"",
81 if (strlen(lastslash
) < STRLITERALLEN("/rootfs")) {
82 ERROR("Failed to detect \"/rootfs\" in string \"%s\"",
88 lastslashidx
= lastslash
- new->dest
;
90 delta
= malloc(lastslashidx
+ 7);
92 ERROR("Failed to allocate memory");
96 memcpy(delta
, new->dest
, lastslashidx
+ 1);
97 memcpy(delta
+ lastslashidx
, "delta0", STRLITERALLEN("delta0"));
98 delta
[lastslashidx
+ STRLITERALLEN("delta0")] = '\0';
100 ret
= mkdir(delta
, 0755);
101 if (ret
< 0 && errno
!= EEXIST
) {
102 SYSERROR("Failed to create directory \"%s\"", delta
);
107 if (am_guest_unpriv()) {
108 ret
= chown_mapped_root(delta
, conf
);
110 WARN("Failed to update ownership of %s", delta
);
113 /* Make workdir for overlayfs.v22 or higher:
114 * The workdir will be
115 * /var/lib/lxc/c2/olwork
116 * and is used to prepare files before they are atomically
117 * switched to the overlay destination. Workdirs need to be on
118 * the same filesystem as the upperdir so it's OK for it to be
121 work
= malloc(lastslashidx
+ 7);
123 ERROR("Failed to allocate memory");
128 memcpy(work
, new->dest
, lastslashidx
+ 1);
129 memcpy(work
+ lastslashidx
, "olwork", STRLITERALLEN("olwork"));
130 work
[lastslashidx
+ STRLITERALLEN("olwork")] = '\0';
132 ret
= mkdir(work
, 0755);
134 SYSERROR("Failed to create directory \"%s\"", work
);
140 if (am_guest_unpriv()) {
141 ret
= chown_mapped_root(work
, conf
);
143 WARN("Failed to update ownership of %s", work
);
147 /* strlen("overlay:") = 8
157 src
= lxc_storage_get_path(orig
->src
, orig
->type
);
158 len
= 8 + strlen(delta
) + 1 + strlen(src
) + 1;
159 new->src
= malloc(len
);
161 ERROR("Failed to allocate memory");
166 ret
= snprintf(new->src
, len
, "overlay:%s:%s", src
, delta
);
168 if (ret
< 0 || (size_t)ret
>= len
) {
169 ERROR("Failed to create string");
172 } else if (!strcmp(orig
->type
, "overlayfs") ||
173 !strcmp(orig
->type
, "overlay")) {
174 char *clean_old_path
, *clean_new_path
;
175 char *lastslash
, *ndelta
, *nsrc
, *odelta
, *osrc
, *s1
, *s2
, *s3
,
178 size_t len
, name_len
;
180 osrc
= strdup(orig
->src
);
182 ERROR("Failed to duplicate string \"%s\"", orig
->src
);
187 if (strncmp(osrc
, "overlay:", 8) == 0)
189 else if (strncmp(osrc
, "overlayfs:", 10) == 0)
192 odelta
= strchr(nsrc
, ':');
194 ERROR("Failed to find \":\" in \"%s\"", nsrc
);
201 ndelta
= must_make_path(lxcpath
, cname
, "delta0", NULL
);
203 ret
= mkdir(ndelta
, 0755);
204 if (ret
< 0 && errno
!= EEXIST
) {
205 SYSERROR("Failed to create directory \"%s\"", ndelta
);
211 if (am_guest_unpriv()) {
212 ret
= chown_mapped_root(ndelta
, conf
);
214 WARN("Failed to update ownership of %s",
218 /* Make workdir for overlayfs.v22 or higher (See the comment
221 lastslash
= strrchr(ndelta
, '/');
223 ERROR("Failed to detect \"/\" in \"%s\"", ndelta
);
229 lastslashidx
= lastslash
- ndelta
;
231 work
= malloc(lastslashidx
+ 7);
235 ERROR("Failed to allocate memory");
239 memcpy(work
, ndelta
, lastslashidx
+ 1);
240 memcpy(work
+ lastslashidx
, "olwork", STRLITERALLEN("olwork"));
241 work
[lastslashidx
+ STRLITERALLEN("olwork")] = '\0';
243 ret
= mkdir(work
, 0755);
244 if (ret
< 0 && errno
!= EEXIST
) {
245 SYSERROR("Failed to create directory \"%s\"", ndelta
);
252 if (am_guest_unpriv()) {
253 ret
= chown_mapped_root(work
, conf
);
255 WARN("Failed to update ownership of %s", work
);
259 /* strlen("overlay:") = 8
269 len
= 8 + strlen(ndelta
) + 1 + strlen(nsrc
) + 1;
270 new->src
= malloc(len
);
274 ERROR("Failed to allocate memory");
277 ret
= snprintf(new->src
, len
, "overlay:%s:%s", nsrc
, ndelta
);
278 if (ret
< 0 || (size_t)ret
>= len
) {
279 ERROR("Failed to create string");
285 ret
= ovl_do_rsync(odelta
, ndelta
, conf
);
291 /* When we create an overlay snapshot of an overlay container in
292 * the snapshot directory under "<lxcpath>/<name>/snaps/" we
293 * don't need to record a dependency. If we would restore would
296 clean_old_path
= lxc_deslashify(oldpath
);
300 clean_new_path
= lxc_deslashify(lxcpath
);
301 if (!clean_new_path
) {
302 free(clean_old_path
);
306 s1
= strrchr(clean_old_path
, '/');
308 ERROR("Failed to detect \"/\" in string \"%s\"", clean_old_path
);
309 free(clean_old_path
);
310 free(clean_new_path
);
314 s2
= strrchr(clean_new_path
, '/');
316 ERROR("Failed to detect \"/\" in string \"%s\"", clean_new_path
);
317 free(clean_old_path
);
318 free(clean_new_path
);
322 if (!strncmp(s1
, "/snaps", STRLITERALLEN("/snaps"))) {
326 } else if (!strncmp(s2
, "/snaps", STRLITERALLEN("/snaps"))) {
329 s3
= (char *)oldname
;
331 free(clean_old_path
);
332 free(clean_new_path
);
337 if (!strncmp(s1
, s2
, len
)) {
340 tmp
= (char *)(s2
+ len
+ 1);
342 free(clean_old_path
);
343 free(clean_new_path
);
347 name_len
= strlen(s3
);
348 if (strncmp(s3
, tmp
, name_len
)) {
349 free(clean_old_path
);
350 free(clean_new_path
);
354 free(clean_old_path
);
355 free(clean_new_path
);
356 return LXC_CLONE_SNAPSHOT
;
359 free(clean_old_path
);
360 free(clean_new_path
);
363 ERROR("overlay clone of %s container is not yet supported",
365 /* Note, supporting this will require ovl_mount supporting
366 * mounting of the underlay. No big deal, just needs to be done.
374 /* To say "lxc-create -t ubuntu -n o1 -B overlay" means you want
375 * "<lxcpath>/<lxcname>/rootfs" to have the created container, while all changes
376 * after starting the container are written to "<lxcpath>/<lxcname>/delta0".
378 int ovl_create(struct lxc_storage
*bdev
, const char *dest
, const char *n
,
379 struct bdev_specs
*specs
)
386 if (len
< 8 || strcmp(dest
+ len
- 7, "/rootfs")) {
387 ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest
);
391 bdev
->dest
= strdup(dest
);
393 ERROR("Failed to duplicate string \"%s\"", dest
);
397 delta
= strdup(dest
);
399 ERROR("Failed to allocate memory");
402 memcpy(delta
+ len
- 6, "delta0", STRLITERALLEN("delta0"));
404 ret
= mkdir_p(delta
, 0755);
406 SYSERROR("Failed to create directory \"%s\"", delta
);
411 /* overlay:lower:upper */
412 newlen
= (2 * len
) + strlen("overlay:") + 2;
413 bdev
->src
= malloc(newlen
);
415 ERROR("Failed to allocate memory");
420 ret
= snprintf(bdev
->src
, newlen
, "overlay:%s:%s", dest
, delta
);
421 if (ret
< 0 || (size_t)ret
>= newlen
) {
422 ERROR("Failed to create string");
427 ret
= mkdir_p(bdev
->dest
, 0755);
429 SYSERROR("Failed to create directory \"%s\"", bdev
->dest
);
438 int ovl_destroy(struct lxc_storage
*orig
)
440 char *upper
= orig
->src
;
442 /* For an overlay container the rootfs is considered immutable
443 * and cannot be removed when restoring from a snapshot.
445 if (orig
->flags
& LXC_STORAGE_INTERNAL_OVERLAY_RESTORE
)
448 if (strncmp(upper
, "overlay:", 8) == 0)
450 else if (strncmp(upper
, "overlayfs:", 10) == 0)
453 upper
= strchr(upper
, ':');
458 return lxc_rmdir_onedev(upper
, NULL
);
461 bool ovl_detect(const char *path
)
463 if (!strncmp(path
, "overlay:", 8))
466 if (!strncmp(path
, "overlayfs:", 10))
472 int ovl_mount(struct lxc_storage
*bdev
)
474 __do_free
char *options
= NULL
,
475 *options_work
= NULL
;
476 char *tmp
, *dup
, *lower
, *upper
;
477 char *work
, *lastslash
;
480 unsigned long mntflags
;
484 if (strcmp(bdev
->type
, "overlay") && strcmp(bdev
->type
, "overlayfs"))
487 if (!bdev
->src
|| !bdev
->dest
)
491 ovl_name
= ovl_detect_name();
493 /* Separately mount it first:
494 * mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
496 dup
= strdup(bdev
->src
);
498 ERROR("Failed to allocate memory");
504 if (strncmp(dup
, "overlay:", 8) == 0)
506 else if (strncmp(dup
, "overlayfs:", 10) == 0)
511 /* support multiple lower layers */
512 while ((tmp
= strstr(upper
, ":/"))) {
518 if (upper
== lower
) {
525 /* if delta doesn't yet exist, create it */
526 ret
= mkdir_p(upper
, 0755);
527 if (ret
< 0 && errno
!= EEXIST
) {
528 SYSERROR("Failed to create directory \"%s\"", upper
);
533 /* overlayfs.v22 or higher needs workdir option:
535 * /var/lib/lxc/c2/delta0
537 * /var/lib/lxc/c2/olwork
539 lastslash
= strrchr(upper
, '/');
541 ERROR("Failed to detect \"/\" in string \"%s\"", upper
);
547 lastslashidx
= lastslash
- upper
;
549 work
= malloc(lastslashidx
+ 7);
551 ERROR("Failed to allocate memory");
556 memcpy(work
, upper
, lastslashidx
+ 1);
557 memcpy(work
+ lastslashidx
, "olwork", STRLITERALLEN("olwork"));
558 work
[lastslashidx
+ STRLITERALLEN("olwork")] = '\0';
560 ret
= parse_mntopts(bdev
->mntopts
, &mntflags
, &mntdata
);
562 ERROR("Failed to parse mount options");
569 ret
= mkdir_p(work
, 0755);
570 if (ret
< 0 && errno
!= EEXIST
) {
571 SYSERROR("Failed to create directory \"%s\"", work
);
580 * We should check whether bdev->src is a blockdev but for now only
581 * support overlays of a basic directory
585 len
= strlen(lower
) + strlen(upper
) +
586 strlen("upperdir=,lowerdir=,") + strlen(mntdata
) + 1;
587 options
= must_realloc(NULL
, len
);
588 ret
= snprintf(options
, len
, "upperdir=%s,lowerdir=%s,%s",
589 upper
, lower
, mntdata
);
591 len2
= strlen(lower
) + strlen(upper
) + strlen(work
) +
592 strlen("upperdir=,lowerdir=,workdir=") +
594 options_work
= must_realloc(NULL
, len2
);
595 ret2
= snprintf(options
, len2
,
596 "upperdir=%s,lowerdir=%s,workdir=%s,%s", upper
,
597 lower
, work
, mntdata
);
599 len
= strlen(lower
) + strlen(upper
) +
600 strlen("upperdir=,lowerdir=") + 1;
601 options
= must_realloc(NULL
, len
);
602 ret
= snprintf(options
, len
, "upperdir=%s,lowerdir=%s", upper
,
605 len2
= strlen(lower
) + strlen(upper
) + strlen(work
) +
606 strlen("upperdir=,lowerdir=,workdir=") + 1;
607 options_work
= must_realloc(NULL
, len2
);
608 ret2
= snprintf(options_work
, len2
,
609 "upperdir=%s,lowerdir=%s,workdir=%s", upper
,
613 if (ret
< 0 || ret
>= len
|| ret2
< 0 || ret2
>= len2
) {
614 ERROR("Failed to create string");
621 /* Assume we need a workdir as we are on a overlay version >= v22. */
622 ret
= ovl_remount_on_enodev(lower
, bdev
->dest
, ovl_name
,
623 MS_MGC_VAL
| mntflags
, options_work
);
625 SYSINFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". "
626 "Retrying without workdir",
627 lower
, bdev
->dest
, options_work
);
629 /* Assume we cannot use a workdir as we are on a version <= v21.
631 ret
= ovl_remount_on_enodev(lower
, bdev
->dest
, ovl_name
,
632 MS_MGC_VAL
| mntflags
, options
);
634 SYSERROR("Failed to mount \"%s\" on \"%s\" with options \"%s\"",
635 lower
, bdev
->dest
, options
);
637 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"",
638 lower
, bdev
->dest
, options
);
640 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower
,
641 bdev
->dest
, options_work
);
649 int ovl_umount(struct lxc_storage
*bdev
)
653 if (strcmp(bdev
->type
, "overlay") && strcmp(bdev
->type
, "overlayfs"))
656 if (!bdev
->src
|| !bdev
->dest
)
659 ret
= umount(bdev
->dest
);
661 SYSERROR("Failed to unmount \"%s\"", bdev
->dest
);
663 TRACE("Unmounted \"%s\"", bdev
->dest
);
668 const char *ovl_get_lower(const char *rootfs_path
)
670 const char *s1
= rootfs_path
;
672 if (strncmp(rootfs_path
, "overlay:", 8) == 0)
674 else if (strncmp(rootfs_path
, "overlayfs:", 10) == 0)
677 s1
= strstr(s1
, ":/");
685 char *ovl_get_rootfs(const char *rootfs_path
, size_t *rootfslen
)
687 char *rootfsdir
= NULL
;
692 if (!rootfs_path
|| !rootfslen
)
695 s1
= strdup(rootfs_path
);
700 if (strncmp(rootfs_path
, "overlay:", 8) == 0)
702 else if (strncmp(rootfs_path
, "overlayfs:", 10) == 0)
705 s3
= strstr(s2
, ":/");
709 rootfsdir
= strdup(s2
);
714 *rootfslen
= strlen(rootfsdir
);
719 int ovl_mkdir(const struct mntent
*mntent
, const struct lxc_rootfs
*rootfs
,
720 const char *lxc_name
, const char *lxc_path
)
722 char lxcpath
[PATH_MAX
];
725 size_t arrlen
, i
, len
, rootfslen
;
728 char *rootfs_dir
= NULL
, *rootfs_path
= NULL
, *upperdir
= NULL
,
731 /* When rootfs == NULL we have a container without a rootfs. */
732 if (rootfs
&& rootfs
->path
)
733 rootfs_path
= rootfs
->path
;
735 opts
= lxc_string_split(mntent
->mnt_opts
, ',');
737 arrlen
= lxc_array_len((void **)opts
);
741 for (i
= 0; i
< arrlen
; i
++) {
742 if (strstr(opts
[i
], "upperdir=") &&
743 (strlen(opts
[i
]) > (len
= strlen("upperdir="))))
744 upperdir
= opts
[i
] + len
;
745 else if (strstr(opts
[i
], "workdir=") &&
746 (strlen(opts
[i
]) > (len
= strlen("workdir="))))
747 workdir
= opts
[i
] + len
;
751 ret
= snprintf(lxcpath
, PATH_MAX
, "%s/%s", lxc_path
, lxc_name
);
752 if (ret
< 0 || ret
>= PATH_MAX
)
755 rootfs_dir
= ovl_get_rootfs(rootfs_path
, &rootfslen
);
759 dirlen
= strlen(lxcpath
);
763 * We neither allow users to create upperdirs and workdirs outside the
764 * containerdir nor inside the rootfs. The latter might be debatable.
765 * When we have a container without a rootfs we skip the checks.
770 ret
= mkdir_p(upperdir
, 0755);
771 else if (!strncmp(upperdir
, lxcpath
, dirlen
) &&
772 strncmp(upperdir
, rootfs_dir
, rootfslen
))
773 ret
= mkdir_p(upperdir
, 0755);
776 SYSWARN("Failed to create directory \"%s\"", upperdir
);
782 ret
= mkdir_p(workdir
, 0755);
783 else if (!strncmp(workdir
, lxcpath
, dirlen
) &&
784 strncmp(workdir
, rootfs_dir
, rootfslen
))
785 ret
= mkdir_p(workdir
, 0755);
788 SYSWARN("Failed to create directory \"%s\"", workdir
);
795 lxc_free_array((void **)opts
, free
);
799 /* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
800 * with overlay lxc.mount.entry entries we need to update absolute paths for
801 * upper- and workdir. This update is done in two locations:
802 * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
803 * independent of each other since lxc_conf->mountlist may contain more mount
804 * entries (e.g. from other included files) than lxc_conf->unexpanded_config.
806 int ovl_update_abs_paths(struct lxc_conf
*lxc_conf
, const char *lxc_path
,
807 const char *lxc_name
, const char *newpath
,
810 char new_upper
[PATH_MAX
], new_work
[PATH_MAX
], old_upper
[PATH_MAX
],
813 struct lxc_list
*iterator
;
814 char *cleanpath
= NULL
;
817 const char *ovl_dirs
[] = {"br", "upperdir", "workdir"};
819 cleanpath
= strdup(newpath
);
823 remove_trailing_slashes(cleanpath
);
826 * We have to update lxc_conf->unexpanded_config separately from
827 * lxc_conf->mount_list.
829 for (i
= 0; i
< sizeof(ovl_dirs
) / sizeof(ovl_dirs
[0]); i
++) {
830 if (!clone_update_unexp_ovl_paths(lxc_conf
, lxc_path
, newpath
,
837 snprintf(old_work
, PATH_MAX
, "workdir=%s/%s", lxc_path
, lxc_name
);
838 if (ret
< 0 || ret
>= PATH_MAX
)
842 snprintf(new_work
, PATH_MAX
, "workdir=%s/%s", cleanpath
, newname
);
843 if (ret
< 0 || ret
>= PATH_MAX
)
846 lxc_list_for_each(iterator
, &lxc_conf
->mount_list
) {
847 char *mnt_entry
= NULL
, *new_mnt_entry
= NULL
, *tmp
= NULL
,
848 *tmp_mnt_entry
= NULL
;
850 mnt_entry
= iterator
->elem
;
852 if (strstr(mnt_entry
, "overlay"))
857 ret
= snprintf(old_upper
, PATH_MAX
, "%s=%s/%s", tmp
, lxc_path
,
859 if (ret
< 0 || ret
>= PATH_MAX
)
862 ret
= snprintf(new_upper
, PATH_MAX
, "%s=%s/%s", tmp
,
864 if (ret
< 0 || ret
>= PATH_MAX
)
867 if (strstr(mnt_entry
, old_upper
)) {
869 lxc_string_replace(old_upper
, new_upper
, mnt_entry
);
872 if (strstr(mnt_entry
, old_work
)) {
874 new_mnt_entry
= lxc_string_replace(
875 old_work
, new_work
, tmp_mnt_entry
);
877 new_mnt_entry
= lxc_string_replace(
878 old_work
, new_work
, mnt_entry
);
882 free(iterator
->elem
);
883 iterator
->elem
= strdup(new_mnt_entry
);
884 } else if (tmp_mnt_entry
) {
885 free(iterator
->elem
);
886 iterator
->elem
= strdup(tmp_mnt_entry
);
899 static int ovl_remount_on_enodev(const char *lower
, const char *target
,
900 const char *name
, unsigned long mountflags
,
904 ret
= mount(lower
, target
, ovl_name
, MS_MGC_VAL
| mountflags
, options
);
905 if (ret
< 0 && errno
== ENODEV
) /* Try other module name. */
906 ret
= mount(lower
, target
,
907 ovl_name
== ovl_version
[0] ? ovl_version
[1]
909 MS_MGC_VAL
| mountflags
, options
);
913 static char *ovl_detect_name(void)
916 char *v
= ovl_version
[0];
920 f
= fopen("/proc/filesystems", "r");
924 while (getline(&line
, &len
, f
) != -1) {
925 if (strcmp(line
, "nodev\toverlayfs\n") == 0) {
936 static int ovl_do_rsync(const char *src
, const char *dest
,
937 struct lxc_conf
*conf
)
940 struct rsync_data_char rdata
= {0};
941 char cmd_output
[PATH_MAX
] = {0};
943 rdata
.src
= (char *)src
;
944 rdata
.dest
= (char *)dest
;
945 if (am_guest_unpriv())
946 ret
= userns_exec_full(conf
, lxc_rsync_exec_wrapper
, &rdata
,
947 "lxc_rsync_exec_wrapper");
949 ret
= run_command(cmd_output
, sizeof(cmd_output
),
950 lxc_rsync_exec_wrapper
, (void *)&rdata
);
952 ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", src
, dest
,
953 cmd_output
[0] != '\0' ? ": " : "",
954 cmd_output
[0] != '\0' ? cmd_output
: "");