2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
7 * Daniel Lezcano <daniel.lezcano at free.fr>
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.
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.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
36 #include "lxccontainer.h"
41 #include "storage_utils.h"
44 lxc_log_define(overlay
, lxc
);
46 static char *ovl_name
;
47 static char *ovl_version
[] = {"overlay", "overlayfs"};
49 static char *ovl_detect_name(void);
50 static int ovl_do_rsync(const char *src
, const char *dest
,
51 struct lxc_conf
*conf
);
52 static int ovl_remount_on_enodev(const char *lower
, const char *target
,
53 const char *name
, unsigned long mountflags
,
56 int ovl_clonepaths(struct lxc_storage
*orig
, struct lxc_storage
*new, const char *oldname
,
57 const char *cname
, const char *oldpath
, const char *lxcpath
,
58 int snap
, uint64_t newsize
, struct lxc_conf
*conf
)
64 ERROR("The overlay storage driver can only be used for "
69 if (!orig
->src
|| !orig
->dest
)
72 new->dest
= must_make_path(lxcpath
, cname
, "rootfs", NULL
);
74 ret
= mkdir_p(new->dest
, 0755);
75 if (ret
< 0 && errno
!= EEXIST
) {
76 SYSERROR("Failed to create directory \"%s\"", new->dest
);
80 if (am_guest_unpriv()) {
81 ret
= chown_mapped_root(new->dest
, conf
);
83 WARN("Failed to update ownership of %s", new->dest
);
86 if (strcmp(orig
->type
, "dir") == 0) {
87 char *delta
, *lastslash
;
89 int ret
, len
, lastslashidx
;
91 /* If we have "/var/lib/lxc/c2/rootfs" then delta will be
92 * "/var/lib/lxc/c2/delta0".
94 lastslash
= strrchr(new->dest
, '/');
96 ERROR("Failed to detect \"/\" in string \"%s\"",
101 if (strlen(lastslash
) < STRLITERALLEN("/rootfs")) {
102 ERROR("Failed to detect \"/rootfs\" in string \"%s\"",
108 lastslashidx
= lastslash
- new->dest
;
110 delta
= malloc(lastslashidx
+ 7);
112 ERROR("Failed to allocate memory");
116 memcpy(delta
, new->dest
, lastslashidx
+ 1);
117 memcpy(delta
+ lastslashidx
, "delta0", STRLITERALLEN("delta0"));
118 delta
[lastslashidx
+ STRLITERALLEN("delta0")] = '\0';
120 ret
= mkdir(delta
, 0755);
121 if (ret
< 0 && errno
!= EEXIST
) {
122 SYSERROR("Failed to create directory \"%s\"", delta
);
127 if (am_guest_unpriv()) {
128 ret
= chown_mapped_root(delta
, conf
);
130 WARN("Failed to update ownership of %s", delta
);
133 /* Make workdir for overlayfs.v22 or higher:
134 * The workdir will be
135 * /var/lib/lxc/c2/olwork
136 * and is used to prepare files before they are atomically
137 * switched to the overlay destination. Workdirs need to be on
138 * the same filesystem as the upperdir so it's OK for it to be
141 work
= malloc(lastslashidx
+ 7);
143 ERROR("Failed to allocate memory");
148 memcpy(work
, new->dest
, lastslashidx
+ 1);
149 memcpy(work
+ lastslashidx
, "olwork", STRLITERALLEN("olwork"));
150 work
[lastslashidx
+ STRLITERALLEN("olwork")] = '\0';
152 ret
= mkdir(work
, 0755);
154 SYSERROR("Failed to create directory \"%s\"", work
);
160 if (am_guest_unpriv()) {
161 ret
= chown_mapped_root(work
, conf
);
163 WARN("Failed to update ownership of %s", work
);
167 /* strlen("overlay:") = 8
177 src
= lxc_storage_get_path(orig
->src
, orig
->type
);
178 len
= 8 + strlen(delta
) + 1 + strlen(src
) + 1;
179 new->src
= malloc(len
);
181 ERROR("Failed to allocate memory");
186 ret
= snprintf(new->src
, len
, "overlay:%s:%s", src
, delta
);
188 if (ret
< 0 || (size_t)ret
>= len
) {
189 ERROR("Failed to create string");
192 } else if (!strcmp(orig
->type
, "overlayfs") ||
193 !strcmp(orig
->type
, "overlay")) {
194 char *clean_old_path
, *clean_new_path
;
195 char *lastslash
, *ndelta
, *nsrc
, *odelta
, *osrc
, *s1
, *s2
, *s3
,
197 int ret
, lastslashidx
;
198 size_t len
, name_len
;
200 osrc
= strdup(orig
->src
);
202 ERROR("Failed to duplicate string \"%s\"", orig
->src
);
207 if (strncmp(osrc
, "overlay:", 8) == 0)
209 else if (strncmp(osrc
, "overlayfs:", 10) == 0)
212 odelta
= strchr(nsrc
, ':');
214 ERROR("Failed to find \":\" in \"%s\"", nsrc
);
221 ndelta
= must_make_path(lxcpath
, cname
, "delta0", NULL
);
223 ret
= mkdir(ndelta
, 0755);
224 if (ret
< 0 && errno
!= EEXIST
) {
225 SYSERROR("Failed to create directory \"%s\"", ndelta
);
231 if (am_guest_unpriv()) {
232 ret
= chown_mapped_root(ndelta
, conf
);
234 WARN("Failed to update ownership of %s",
238 /* Make workdir for overlayfs.v22 or higher (See the comment
241 lastslash
= strrchr(ndelta
, '/');
243 ERROR("Failed to detect \"/\" in \"%s\"", ndelta
);
249 lastslashidx
= lastslash
- ndelta
;
251 work
= malloc(lastslashidx
+ 7);
255 ERROR("Failed to allocate memory");
259 memcpy(work
, ndelta
, lastslashidx
+ 1);
260 memcpy(work
+ lastslashidx
, "olwork", STRLITERALLEN("olwork"));
261 work
[lastslashidx
+ STRLITERALLEN("olwork")] = '\0';
263 ret
= mkdir(work
, 0755);
264 if (ret
< 0 && errno
!= EEXIST
) {
265 SYSERROR("Failed to create directory \"%s\"", ndelta
);
272 if (am_guest_unpriv()) {
273 ret
= chown_mapped_root(work
, conf
);
275 WARN("Failed to update ownership of %s", work
);
279 /* strlen("overlay:") = 8
289 len
= 8 + strlen(ndelta
) + 1 + strlen(nsrc
) + 1;
290 new->src
= malloc(len
);
294 ERROR("Failed to allocate memory");
297 ret
= snprintf(new->src
, len
, "overlay:%s:%s", nsrc
, ndelta
);
298 if (ret
< 0 || (size_t)ret
>= len
) {
299 ERROR("Failed to create string");
305 ret
= ovl_do_rsync(odelta
, ndelta
, conf
);
311 /* When we create an overlay snapshot of an overlay container in
312 * the snapshot directory under "<lxcpath>/<name>/snaps/" we
313 * don't need to record a dependency. If we would restore would
316 clean_old_path
= lxc_deslashify(oldpath
);
320 clean_new_path
= lxc_deslashify(lxcpath
);
321 if (!clean_new_path
) {
322 free(clean_old_path
);
326 s1
= strrchr(clean_old_path
, '/');
328 ERROR("Failed to detect \"/\" in string \"%s\"", clean_old_path
);
329 free(clean_old_path
);
330 free(clean_new_path
);
334 s2
= strrchr(clean_new_path
, '/');
336 ERROR("Failed to detect \"/\" in string \"%s\"", clean_new_path
);
337 free(clean_old_path
);
338 free(clean_new_path
);
342 if (!strncmp(s1
, "/snaps", STRLITERALLEN("/snaps"))) {
346 } else if (!strncmp(s2
, "/snaps", STRLITERALLEN("/snaps"))) {
349 s3
= (char *)oldname
;
351 free(clean_old_path
);
352 free(clean_new_path
);
357 if (!strncmp(s1
, s2
, len
)) {
360 tmp
= (char *)(s2
+ len
+ 1);
362 free(clean_old_path
);
363 free(clean_new_path
);
367 name_len
= strlen(s3
);
368 if (strncmp(s3
, tmp
, name_len
)) {
369 free(clean_old_path
);
370 free(clean_new_path
);
374 free(clean_old_path
);
375 free(clean_new_path
);
376 return LXC_CLONE_SNAPSHOT
;
379 free(clean_old_path
);
380 free(clean_new_path
);
383 ERROR("overlay clone of %s container is not yet supported",
385 /* Note, supporting this will require ovl_mount supporting
386 * mounting of the underlay. No big deal, just needs to be done.
394 /* To say "lxc-create -t ubuntu -n o1 -B overlay" means you want
395 * "<lxcpath>/<lxcname>/rootfs" to have the created container, while all changes
396 * after starting the container are written to "<lxcpath>/<lxcname>/delta0".
398 int ovl_create(struct lxc_storage
*bdev
, const char *dest
, const char *n
,
399 struct bdev_specs
*specs
)
406 if (len
< 8 || strcmp(dest
+ len
- 7, "/rootfs")) {
407 ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest
);
411 bdev
->dest
= strdup(dest
);
413 ERROR("Failed to duplicate string \"%s\"", dest
);
417 delta
= strdup(dest
);
419 ERROR("Failed to allocate memory");
422 memcpy(delta
+ len
- 6, "delta0", STRLITERALLEN("delta0"));
424 ret
= mkdir_p(delta
, 0755);
426 SYSERROR("Failed to create directory \"%s\"", delta
);
431 /* overlay:lower:upper */
432 newlen
= (2 * len
) + strlen("overlay:") + 2;
433 bdev
->src
= malloc(newlen
);
435 ERROR("Failed to allocate memory");
440 ret
= snprintf(bdev
->src
, newlen
, "overlay:%s:%s", dest
, delta
);
441 if (ret
< 0 || (size_t)ret
>= newlen
) {
442 ERROR("Failed to create string");
447 ret
= mkdir_p(bdev
->dest
, 0755);
449 SYSERROR("Failed to create directory \"%s\"", bdev
->dest
);
458 int ovl_destroy(struct lxc_storage
*orig
)
460 char *upper
= orig
->src
;
462 /* For an overlay container the rootfs is considered immutable
463 * and cannot be removed when restoring from a snapshot.
465 if (orig
->flags
& LXC_STORAGE_INTERNAL_OVERLAY_RESTORE
)
468 if (strncmp(upper
, "overlay:", 8) == 0)
470 else if (strncmp(upper
, "overlayfs:", 10) == 0)
473 upper
= strchr(upper
, ':');
478 return lxc_rmdir_onedev(upper
, NULL
);
481 bool ovl_detect(const char *path
)
483 if (!strncmp(path
, "overlay:", 8))
486 if (!strncmp(path
, "overlayfs:", 10))
492 int ovl_mount(struct lxc_storage
*bdev
)
494 char *tmp
, *options
, *dup
, *lower
, *upper
;
495 char *options_work
, *work
, *lastslash
;
498 unsigned long mntflags
;
502 if (strcmp(bdev
->type
, "overlay") && strcmp(bdev
->type
, "overlayfs"))
505 if (!bdev
->src
|| !bdev
->dest
)
509 ovl_name
= ovl_detect_name();
511 /* Separately mount it first:
512 * mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
514 dup
= strdup(bdev
->src
);
516 ERROR("Failed to allocate memory");
522 if (strncmp(dup
, "overlay:", 8) == 0)
524 else if (strncmp(dup
, "overlayfs:", 10) == 0)
529 /* support multiple lower layers */
530 while ((tmp
= strstr(upper
, ":/"))) {
536 if (upper
== lower
) {
543 /* if delta doesn't yet exist, create it */
544 ret
= mkdir_p(upper
, 0755);
545 if (ret
< 0 && errno
!= EEXIST
) {
546 SYSERROR("Failed to create directory \"%s\"", upper
);
551 /* overlayfs.v22 or higher needs workdir option:
553 * /var/lib/lxc/c2/delta0
555 * /var/lib/lxc/c2/olwork
557 lastslash
= strrchr(upper
, '/');
559 ERROR("Failed to detect \"/\" in string \"%s\"", upper
);
565 lastslashidx
= lastslash
- upper
;
567 work
= malloc(lastslashidx
+ 7);
569 ERROR("Failed to allocate memory");
574 memcpy(work
, upper
, lastslashidx
+ 1);
575 memcpy(work
+ lastslashidx
, "olwork", STRLITERALLEN("olwork"));
576 work
[lastslashidx
+ STRLITERALLEN("olwork")] = '\0';
578 ret
= parse_mntopts(bdev
->mntopts
, &mntflags
, &mntdata
);
580 ERROR("Failed to parse mount options");
587 ret
= mkdir_p(work
, 0755);
588 if (ret
< 0 && errno
!= EEXIST
) {
589 SYSERROR("Failed to create directory \"%s\"", work
);
598 * We should check whether bdev->src is a blockdev but for now only
599 * support overlays of a basic directory
603 len
= strlen(lower
) + strlen(upper
) +
604 strlen("upperdir=,lowerdir=,") + strlen(mntdata
) + 1;
605 options
= alloca(len
);
606 ret
= snprintf(options
, len
, "upperdir=%s,lowerdir=%s,%s",
607 upper
, lower
, mntdata
);
609 len2
= strlen(lower
) + strlen(upper
) + strlen(work
) +
610 strlen("upperdir=,lowerdir=,workdir=") +
612 options_work
= alloca(len2
);
613 ret2
= snprintf(options
, len2
,
614 "upperdir=%s,lowerdir=%s,workdir=%s,%s", upper
,
615 lower
, work
, mntdata
);
617 len
= strlen(lower
) + strlen(upper
) +
618 strlen("upperdir=,lowerdir=") + 1;
619 options
= alloca(len
);
620 ret
= snprintf(options
, len
, "upperdir=%s,lowerdir=%s", upper
,
623 len2
= strlen(lower
) + strlen(upper
) + strlen(work
) +
624 strlen("upperdir=,lowerdir=,workdir=") + 1;
625 options_work
= alloca(len2
);
626 ret2
= snprintf(options_work
, len2
,
627 "upperdir=%s,lowerdir=%s,workdir=%s", upper
,
631 if (ret
< 0 || ret
>= len
|| ret2
< 0 || ret2
>= len2
) {
632 ERROR("Failed to create string");
639 /* Assume we need a workdir as we are on a overlay version >= v22. */
640 ret
= ovl_remount_on_enodev(lower
, bdev
->dest
, ovl_name
,
641 MS_MGC_VAL
| mntflags
, options_work
);
643 SYSINFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". "
644 "Retrying without workdir",
645 lower
, bdev
->dest
, options_work
);
647 /* Assume we cannot use a workdir as we are on a version <= v21.
649 ret
= ovl_remount_on_enodev(lower
, bdev
->dest
, ovl_name
,
650 MS_MGC_VAL
| mntflags
, options
);
652 SYSERROR("Failed to mount \"%s\" on \"%s\" with options \"%s\"",
653 lower
, bdev
->dest
, options
);
655 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"",
656 lower
, bdev
->dest
, options
);
658 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower
,
659 bdev
->dest
, options_work
);
667 int ovl_umount(struct lxc_storage
*bdev
)
671 if (strcmp(bdev
->type
, "overlay") && strcmp(bdev
->type
, "overlayfs"))
674 if (!bdev
->src
|| !bdev
->dest
)
677 ret
= umount(bdev
->dest
);
679 SYSERROR("Failed to unmount \"%s\"", bdev
->dest
);
681 TRACE("Unmounted \"%s\"", bdev
->dest
);
686 const char *ovl_get_lower(const char *rootfs_path
)
688 const char *s1
= rootfs_path
;
690 if (strncmp(rootfs_path
, "overlay:", 8) == 0)
692 else if (strncmp(rootfs_path
, "overlayfs:", 10) == 0)
695 s1
= strstr(s1
, ":/");
703 char *ovl_get_rootfs(const char *rootfs_path
, size_t *rootfslen
)
705 char *rootfsdir
= NULL
;
710 if (!rootfs_path
|| !rootfslen
)
713 s1
= strdup(rootfs_path
);
718 if (strncmp(rootfs_path
, "overlay:", 8) == 0)
720 else if (strncmp(rootfs_path
, "overlayfs:", 10) == 0)
723 s3
= strstr(s2
, ":/");
727 rootfsdir
= strdup(s2
);
732 *rootfslen
= strlen(rootfsdir
);
737 int ovl_mkdir(const struct mntent
*mntent
, const struct lxc_rootfs
*rootfs
,
738 const char *lxc_name
, const char *lxc_path
)
740 char lxcpath
[PATH_MAX
];
743 size_t arrlen
, i
, len
, rootfslen
;
746 char *rootfs_dir
= NULL
, *rootfs_path
= NULL
, *upperdir
= NULL
,
749 /* When rootfs == NULL we have a container without a rootfs. */
750 if (rootfs
&& rootfs
->path
)
751 rootfs_path
= rootfs
->path
;
753 opts
= lxc_string_split(mntent
->mnt_opts
, ',');
755 arrlen
= lxc_array_len((void **)opts
);
759 for (i
= 0; i
< arrlen
; i
++) {
760 if (strstr(opts
[i
], "upperdir=") &&
761 (strlen(opts
[i
]) > (len
= strlen("upperdir="))))
762 upperdir
= opts
[i
] + len
;
763 else if (strstr(opts
[i
], "workdir=") &&
764 (strlen(opts
[i
]) > (len
= strlen("workdir="))))
765 workdir
= opts
[i
] + len
;
769 ret
= snprintf(lxcpath
, PATH_MAX
, "%s/%s", lxc_path
, lxc_name
);
770 if (ret
< 0 || ret
>= PATH_MAX
)
773 rootfs_dir
= ovl_get_rootfs(rootfs_path
, &rootfslen
);
777 dirlen
= strlen(lxcpath
);
781 * We neither allow users to create upperdirs and workdirs outside the
782 * containerdir nor inside the rootfs. The latter might be debatable.
783 * When we have a container without a rootfs we skip the checks.
788 ret
= mkdir_p(upperdir
, 0755);
789 else if (!strncmp(upperdir
, lxcpath
, dirlen
) &&
790 strncmp(upperdir
, rootfs_dir
, rootfslen
))
791 ret
= mkdir_p(upperdir
, 0755);
794 SYSWARN("Failed to create directory \"%s\"", upperdir
);
800 ret
= mkdir_p(workdir
, 0755);
801 else if (!strncmp(workdir
, lxcpath
, dirlen
) &&
802 strncmp(workdir
, rootfs_dir
, rootfslen
))
803 ret
= mkdir_p(workdir
, 0755);
806 SYSWARN("Failed to create directory \"%s\"", workdir
);
813 lxc_free_array((void **)opts
, free
);
817 /* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
818 * with overlay lxc.mount.entry entries we need to update absolute paths for
819 * upper- and workdir. This update is done in two locations:
820 * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
821 * independent of each other since lxc_conf->mountlist may contain more mount
822 * entries (e.g. from other included files) than lxc_conf->unexpanded_config.
824 int ovl_update_abs_paths(struct lxc_conf
*lxc_conf
, const char *lxc_path
,
825 const char *lxc_name
, const char *newpath
,
828 char new_upper
[PATH_MAX
], new_work
[PATH_MAX
], old_upper
[PATH_MAX
],
831 struct lxc_list
*iterator
;
832 char *cleanpath
= NULL
;
835 const char *ovl_dirs
[] = {"br", "upperdir", "workdir"};
837 cleanpath
= strdup(newpath
);
841 remove_trailing_slashes(cleanpath
);
844 * We have to update lxc_conf->unexpanded_config separately from
845 * lxc_conf->mount_list.
847 for (i
= 0; i
< sizeof(ovl_dirs
) / sizeof(ovl_dirs
[0]); i
++) {
848 if (!clone_update_unexp_ovl_paths(lxc_conf
, lxc_path
, newpath
,
855 snprintf(old_work
, PATH_MAX
, "workdir=%s/%s", lxc_path
, lxc_name
);
856 if (ret
< 0 || ret
>= PATH_MAX
)
860 snprintf(new_work
, PATH_MAX
, "workdir=%s/%s", cleanpath
, newname
);
861 if (ret
< 0 || ret
>= PATH_MAX
)
864 lxc_list_for_each(iterator
, &lxc_conf
->mount_list
) {
865 char *mnt_entry
= NULL
, *new_mnt_entry
= NULL
, *tmp
= NULL
,
866 *tmp_mnt_entry
= NULL
;
868 mnt_entry
= iterator
->elem
;
870 if (strstr(mnt_entry
, "overlay"))
875 ret
= snprintf(old_upper
, PATH_MAX
, "%s=%s/%s", tmp
, lxc_path
,
877 if (ret
< 0 || ret
>= PATH_MAX
)
880 ret
= snprintf(new_upper
, PATH_MAX
, "%s=%s/%s", tmp
,
882 if (ret
< 0 || ret
>= PATH_MAX
)
885 if (strstr(mnt_entry
, old_upper
)) {
887 lxc_string_replace(old_upper
, new_upper
, mnt_entry
);
890 if (strstr(mnt_entry
, old_work
)) {
892 new_mnt_entry
= lxc_string_replace(
893 old_work
, new_work
, tmp_mnt_entry
);
895 new_mnt_entry
= lxc_string_replace(
896 old_work
, new_work
, mnt_entry
);
900 free(iterator
->elem
);
901 iterator
->elem
= strdup(new_mnt_entry
);
902 } else if (tmp_mnt_entry
) {
903 free(iterator
->elem
);
904 iterator
->elem
= strdup(tmp_mnt_entry
);
917 static int ovl_remount_on_enodev(const char *lower
, const char *target
,
918 const char *name
, unsigned long mountflags
,
922 ret
= mount(lower
, target
, ovl_name
, MS_MGC_VAL
| mountflags
, options
);
923 if (ret
< 0 && errno
== ENODEV
) /* Try other module name. */
924 ret
= mount(lower
, target
,
925 ovl_name
== ovl_version
[0] ? ovl_version
[1]
927 MS_MGC_VAL
| mountflags
, options
);
931 static char *ovl_detect_name(void)
934 char *v
= ovl_version
[0];
938 f
= fopen("/proc/filesystems", "r");
942 while (getline(&line
, &len
, f
) != -1) {
943 if (strcmp(line
, "nodev\toverlayfs\n") == 0) {
954 static int ovl_do_rsync(const char *src
, const char *dest
,
955 struct lxc_conf
*conf
)
958 struct rsync_data_char rdata
= {0};
959 char cmd_output
[PATH_MAX
] = {0};
961 rdata
.src
= (char *)src
;
962 rdata
.dest
= (char *)dest
;
963 if (am_guest_unpriv())
964 ret
= userns_exec_full(conf
, lxc_rsync_exec_wrapper
, &rdata
,
965 "lxc_rsync_exec_wrapper");
967 ret
= run_command(cmd_output
, sizeof(cmd_output
),
968 lxc_rsync_exec_wrapper
, (void *)&rdata
);
970 ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", src
, dest
,
971 cmd_output
[0] != '\0' ? ": " : "",
972 cmd_output
[0] != '\0' ? cmd_output
: "");