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
33 #include "lxccontainer.h"
37 #include "storage_utils.h"
40 lxc_log_define(overlay
, lxc
);
42 static char *ovl_name
;
43 static char *ovl_version
[] = {"overlay", "overlayfs"};
45 static char *ovl_detect_name(void);
46 static int ovl_do_rsync(const char *src
, const char *dest
,
47 struct lxc_conf
*conf
);
48 static int ovl_remount_on_enodev(const char *lower
, const char *target
,
49 const char *name
, unsigned long mountflags
,
52 int ovl_clonepaths(struct lxc_storage
*orig
, struct lxc_storage
*new, const char *oldname
,
53 const char *cname
, const char *oldpath
, const char *lxcpath
,
54 int snap
, uint64_t newsize
, struct lxc_conf
*conf
)
60 ERROR("The overlay storage driver can only be used for "
65 if (!orig
->src
|| !orig
->dest
)
68 new->dest
= must_make_path(lxcpath
, cname
, "rootfs", NULL
);
70 ret
= mkdir_p(new->dest
, 0755);
71 if (ret
< 0 && errno
!= EEXIST
) {
72 SYSERROR("Failed to create directory \"%s\"", new->dest
);
76 if (am_guest_unpriv()) {
77 ret
= chown_mapped_root(new->dest
, conf
);
79 WARN("Failed to update ownership of %s", new->dest
);
82 if (strcmp(orig
->type
, "dir") == 0) {
83 char *delta
, *lastslash
;
85 int ret
, len
, lastslashidx
;
87 /* If we have "/var/lib/lxc/c2/rootfs" then delta will be
88 * "/var/lib/lxc/c2/delta0".
90 lastslash
= strrchr(new->dest
, '/');
92 ERROR("Failed to detect \"/\" in string \"%s\"",
97 if (strlen(lastslash
) < (sizeof("/rootfs") - 1)) {
98 ERROR("Failed to detect \"/rootfs\" in string \"%s\"",
104 lastslashidx
= lastslash
- new->dest
;
106 delta
= malloc(lastslashidx
+ 7);
108 ERROR("Failed to allocate memory");
112 memcpy(delta
, new->dest
, lastslashidx
+ 1);
113 memcpy(delta
+ lastslashidx
, "delta0", sizeof("delta0") - 1);
114 delta
[lastslashidx
+ sizeof("delta0") - 1] = '\0';
116 ret
= mkdir(delta
, 0755);
117 if (ret
< 0 && errno
!= EEXIST
) {
118 SYSERROR("Failed to create directory \"%s\"", delta
);
123 if (am_guest_unpriv()) {
124 ret
= chown_mapped_root(delta
, conf
);
126 WARN("Failed to update ownership of %s", delta
);
129 /* Make workdir for overlayfs.v22 or higher:
130 * The workdir will be
131 * /var/lib/lxc/c2/olwork
132 * and is used to prepare files before they are atomically
133 * switched to the overlay destination. Workdirs need to be on
134 * the same filesystem as the upperdir so it's OK for it to be
137 work
= malloc(lastslashidx
+ 7);
139 ERROR("Failed to allocate memory");
144 memcpy(work
, new->dest
, lastslashidx
+ 1);
145 memcpy(work
+ lastslashidx
, "olwork", sizeof("olwork") - 1);
146 work
[lastslashidx
+ sizeof("olwork") - 1] = '\0';
148 ret
= mkdir(work
, 0755);
150 SYSERROR("Failed to create directory \"%s\"", work
);
156 if (am_guest_unpriv()) {
157 ret
= chown_mapped_root(work
, conf
);
159 WARN("Failed to update ownership of %s", work
);
163 /* strlen("overlay:") = 8
173 src
= lxc_storage_get_path(orig
->src
, orig
->type
);
174 len
= 8 + strlen(delta
) + 1 + strlen(src
) + 1;
175 new->src
= malloc(len
);
177 ERROR("Failed to allocate memory");
182 ret
= snprintf(new->src
, len
, "overlay:%s:%s", src
, delta
);
184 if (ret
< 0 || (size_t)ret
>= len
) {
185 ERROR("Failed to create string");
188 } else if (!strcmp(orig
->type
, "overlayfs") ||
189 !strcmp(orig
->type
, "overlay")) {
190 char *clean_old_path
, *clean_new_path
;
191 char *lastslash
, *ndelta
, *nsrc
, *odelta
, *osrc
, *s1
, *s2
, *s3
,
193 int ret
, lastslashidx
;
194 size_t len
, name_len
;
196 osrc
= strdup(orig
->src
);
198 ERROR("Failed to duplicate string \"%s\"", orig
->src
);
203 if (strncmp(osrc
, "overlay:", 8) == 0)
205 else if (strncmp(osrc
, "overlayfs:", 10) == 0)
208 odelta
= strchr(nsrc
, ':');
210 ERROR("Failed to find \":\" in \"%s\"", nsrc
);
217 ndelta
= must_make_path(lxcpath
, cname
, "delta0", NULL
);
219 ret
= mkdir(ndelta
, 0755);
220 if (ret
< 0 && errno
!= EEXIST
) {
221 SYSERROR("Failed to create directory \"%s\"", ndelta
);
227 if (am_guest_unpriv()) {
228 ret
= chown_mapped_root(ndelta
, conf
);
230 WARN("Failed to update ownership of %s",
234 /* Make workdir for overlayfs.v22 or higher (See the comment
237 lastslash
= strrchr(ndelta
, '/');
239 ERROR("Failed to detect \"/\" in \"%s\"", ndelta
);
245 lastslashidx
= lastslash
- ndelta
;
247 work
= malloc(lastslashidx
+ 7);
251 ERROR("Failed to allocate memory");
255 memcpy(work
, ndelta
, lastslashidx
+ 1);
256 memcpy(work
+ lastslashidx
, "olwork", sizeof("olwork") - 1);
257 work
[lastslashidx
+ sizeof("olwork") - 1] = '\0';
259 ret
= mkdir(work
, 0755);
260 if (ret
< 0 && errno
!= EEXIST
) {
261 SYSERROR("Failed to create directory \"%s\"", ndelta
);
268 if (am_guest_unpriv()) {
269 ret
= chown_mapped_root(work
, conf
);
271 WARN("Failed to update ownership of %s", work
);
275 /* strlen("overlay:") = 8
285 len
= 8 + strlen(ndelta
) + 1 + strlen(nsrc
) + 1;
286 new->src
= malloc(len
);
290 ERROR("Failed to allocate memory");
293 ret
= snprintf(new->src
, len
, "overlay:%s:%s", nsrc
, ndelta
);
294 if (ret
< 0 || (size_t)ret
>= len
) {
295 ERROR("Failed to create string");
301 ret
= ovl_do_rsync(odelta
, ndelta
, conf
);
307 /* When we create an overlay snapshot of an overlay container in
308 * the snapshot directory under "<lxcpath>/<name>/snaps/" we
309 * don't need to record a dependency. If we would restore would
312 clean_old_path
= lxc_deslashify(oldpath
);
316 clean_new_path
= lxc_deslashify(lxcpath
);
317 if (!clean_new_path
) {
318 free(clean_old_path
);
322 s1
= strrchr(clean_old_path
, '/');
324 ERROR("Failed to detect \"/\" in string \"%s\"", clean_old_path
);
325 free(clean_old_path
);
326 free(clean_new_path
);
330 s2
= strrchr(clean_new_path
, '/');
332 ERROR("Failed to detect \"/\" in string \"%s\"", clean_new_path
);
333 free(clean_old_path
);
334 free(clean_new_path
);
338 if (!strncmp(s1
, "/snaps", sizeof("/snaps") - 1)) {
342 } else if (!strncmp(s2
, "/snaps", sizeof("/snaps") - 1)) {
345 s3
= (char *)oldname
;
347 free(clean_old_path
);
348 free(clean_new_path
);
353 if (!strncmp(s1
, s2
, len
)) {
356 tmp
= (char *)(s2
+ len
+ 1);
358 free(clean_old_path
);
359 free(clean_new_path
);
363 name_len
= strlen(s3
);
364 if (strncmp(s3
, tmp
, name_len
)) {
365 free(clean_old_path
);
366 free(clean_new_path
);
370 free(clean_old_path
);
371 free(clean_new_path
);
372 return LXC_CLONE_SNAPSHOT
;
375 free(clean_old_path
);
376 free(clean_new_path
);
379 ERROR("overlay clone of %s container is not yet supported",
381 /* Note, supporting this will require ovl_mount supporting
382 * mounting of the underlay. No big deal, just needs to be done.
390 /* To say "lxc-create -t ubuntu -n o1 -B overlay" means you want
391 * "<lxcpath>/<lxcname>/rootfs" to have the created container, while all changes
392 * after starting the container are written to "<lxcpath>/<lxcname>/delta0".
394 int ovl_create(struct lxc_storage
*bdev
, const char *dest
, const char *n
,
395 struct bdev_specs
*specs
)
402 if (len
< 8 || strcmp(dest
+ len
- 7, "/rootfs")) {
403 ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest
);
407 bdev
->dest
= strdup(dest
);
409 ERROR("Failed to duplicate string \"%s\"", dest
);
413 delta
= strdup(dest
);
415 ERROR("Failed to allocate memory");
418 memcpy(delta
+ len
- 6, "delta0", sizeof("delta0") - 1);
420 ret
= mkdir_p(delta
, 0755);
422 SYSERROR("Failed to create directory \"%s\"", delta
);
427 /* overlay:lower:upper */
428 newlen
= (2 * len
) + strlen("overlay:") + 2;
429 bdev
->src
= malloc(newlen
);
431 ERROR("Failed to allocate memory");
436 ret
= snprintf(bdev
->src
, newlen
, "overlay:%s:%s", dest
, delta
);
437 if (ret
< 0 || (size_t)ret
>= newlen
) {
438 ERROR("Failed to create string");
443 ret
= mkdir_p(bdev
->dest
, 0755);
445 SYSERROR("Failed to create directory \"%s\"", bdev
->dest
);
454 int ovl_destroy(struct lxc_storage
*orig
)
456 char *upper
= orig
->src
;
458 /* For an overlay container the rootfs is considered immutable
459 * and cannot be removed when restoring from a snapshot.
461 if (orig
->flags
& LXC_STORAGE_INTERNAL_OVERLAY_RESTORE
)
464 if (strncmp(upper
, "overlay:", 8) == 0)
466 else if (strncmp(upper
, "overlayfs:", 10) == 0)
469 upper
= strchr(upper
, ':');
474 return lxc_rmdir_onedev(upper
, NULL
);
477 bool ovl_detect(const char *path
)
479 if (!strncmp(path
, "overlay:", 8))
482 if (!strncmp(path
, "overlayfs:", 10))
488 int ovl_mount(struct lxc_storage
*bdev
)
490 char *tmp
, *options
, *dup
, *lower
, *upper
;
491 char *options_work
, *work
, *lastslash
;
494 unsigned long mntflags
;
498 if (strcmp(bdev
->type
, "overlay") && strcmp(bdev
->type
, "overlayfs"))
501 if (!bdev
->src
|| !bdev
->dest
)
505 ovl_name
= ovl_detect_name();
507 /* Separately mount it first:
508 * mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
510 dup
= strdup(bdev
->src
);
512 ERROR("Failed to allocate memory");
518 if (strncmp(dup
, "overlay:", 8) == 0)
520 else if (strncmp(dup
, "overlayfs:", 10) == 0)
525 /* support multiple lower layers */
526 while ((tmp
= strstr(upper
, ":/"))) {
532 if (upper
== lower
) {
539 /* if delta doesn't yet exist, create it */
540 ret
= mkdir_p(upper
, 0755);
541 if (ret
< 0 && errno
!= EEXIST
) {
542 SYSERROR("Failed to create directory \"%s\"", upper
);
547 /* overlayfs.v22 or higher needs workdir option:
549 * /var/lib/lxc/c2/delta0
551 * /var/lib/lxc/c2/olwork
553 lastslash
= strrchr(upper
, '/');
555 ERROR("Failed to detect \"/\" in string \"%s\"", upper
);
561 lastslashidx
= lastslash
- upper
;
563 work
= malloc(lastslashidx
+ 7);
565 ERROR("Failed to allocate memory");
570 memcpy(work
, upper
, lastslashidx
+ 1);
571 memcpy(work
+ lastslashidx
, "olwork", sizeof("olwork") - 1);
572 work
[lastslashidx
+ sizeof("olwork") - 1] = '\0';
574 ret
= parse_mntopts(bdev
->mntopts
, &mntflags
, &mntdata
);
576 ERROR("Failed to parse mount options");
583 ret
= mkdir_p(work
, 0755);
584 if (ret
< 0 && errno
!= EEXIST
) {
585 SYSERROR("Failed to create directory \"%s\"", work
);
594 * We should check whether bdev->src is a blockdev but for now only
595 * support overlays of a basic directory
599 len
= strlen(lower
) + strlen(upper
) +
600 strlen("upperdir=,lowerdir=,") + strlen(mntdata
) + 1;
601 options
= alloca(len
);
602 ret
= snprintf(options
, len
, "upperdir=%s,lowerdir=%s,%s",
603 upper
, lower
, mntdata
);
605 len2
= strlen(lower
) + strlen(upper
) + strlen(work
) +
606 strlen("upperdir=,lowerdir=,workdir=") +
608 options_work
= alloca(len2
);
609 ret2
= snprintf(options
, len2
,
610 "upperdir=%s,lowerdir=%s,workdir=%s,%s", upper
,
611 lower
, work
, mntdata
);
613 len
= strlen(lower
) + strlen(upper
) +
614 strlen("upperdir=,lowerdir=") + 1;
615 options
= alloca(len
);
616 ret
= snprintf(options
, len
, "upperdir=%s,lowerdir=%s", upper
,
619 len2
= strlen(lower
) + strlen(upper
) + strlen(work
) +
620 strlen("upperdir=,lowerdir=,workdir=") + 1;
621 options_work
= alloca(len2
);
622 ret2
= snprintf(options_work
, len2
,
623 "upperdir=%s,lowerdir=%s,workdir=%s", upper
,
627 if (ret
< 0 || ret
>= len
|| ret2
< 0 || ret2
>= len2
) {
628 ERROR("Failed to create string");
635 /* Assume we need a workdir as we are on a overlay version >= v22. */
636 ret
= ovl_remount_on_enodev(lower
, bdev
->dest
, ovl_name
,
637 MS_MGC_VAL
| mntflags
, options_work
);
639 INFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". "
640 "Retrying without workdir: %s",
641 lower
, bdev
->dest
, options_work
, strerror(errno
));
643 /* Assume we cannot use a workdir as we are on a version <= v21.
645 ret
= ovl_remount_on_enodev(lower
, bdev
->dest
, ovl_name
,
646 MS_MGC_VAL
| mntflags
, options
);
648 SYSERROR("Failed to mount \"%s\" on \"%s\" with "
649 "options \"%s\": %s",
650 lower
, bdev
->dest
, options
, strerror(errno
));
652 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"",
653 lower
, bdev
->dest
, options
);
655 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower
,
656 bdev
->dest
, options_work
);
664 int ovl_umount(struct lxc_storage
*bdev
)
668 if (strcmp(bdev
->type
, "overlay") && strcmp(bdev
->type
, "overlayfs"))
671 if (!bdev
->src
|| !bdev
->dest
)
674 ret
= umount(bdev
->dest
);
676 SYSERROR("Failed to unmount \"%s\"", bdev
->dest
);
678 TRACE("Unmounted \"%s\"", bdev
->dest
);
683 const char *ovl_get_lower(const char *rootfs_path
)
685 const char *s1
= rootfs_path
;
687 if (strncmp(rootfs_path
, "overlay:", 8) == 0)
689 else if (strncmp(rootfs_path
, "overlayfs:", 10) == 0)
692 s1
= strstr(s1
, ":/");
700 char *ovl_get_rootfs(const char *rootfs_path
, size_t *rootfslen
)
702 char *rootfsdir
= NULL
;
707 if (!rootfs_path
|| !rootfslen
)
710 s1
= strdup(rootfs_path
);
715 if (strncmp(rootfs_path
, "overlay:", 8) == 0)
717 else if (strncmp(rootfs_path
, "overlayfs:", 10) == 0)
720 s3
= strstr(s2
, ":/");
724 rootfsdir
= strdup(s2
);
729 *rootfslen
= strlen(rootfsdir
);
734 int ovl_mkdir(const struct mntent
*mntent
, const struct lxc_rootfs
*rootfs
,
735 const char *lxc_name
, const char *lxc_path
)
737 char lxcpath
[MAXPATHLEN
];
740 size_t arrlen
, i
, len
, rootfslen
;
743 char *rootfs_dir
= NULL
, *rootfs_path
= NULL
, *upperdir
= NULL
,
746 /* When rootfs == NULL we have a container without a rootfs. */
747 if (rootfs
&& rootfs
->path
)
748 rootfs_path
= rootfs
->path
;
750 opts
= lxc_string_split(mntent
->mnt_opts
, ',');
752 arrlen
= lxc_array_len((void **)opts
);
756 for (i
= 0; i
< arrlen
; i
++) {
757 if (strstr(opts
[i
], "upperdir=") &&
758 (strlen(opts
[i
]) > (len
= strlen("upperdir="))))
759 upperdir
= opts
[i
] + len
;
760 else if (strstr(opts
[i
], "workdir=") &&
761 (strlen(opts
[i
]) > (len
= strlen("workdir="))))
762 workdir
= opts
[i
] + len
;
766 ret
= snprintf(lxcpath
, MAXPATHLEN
, "%s/%s", lxc_path
, lxc_name
);
767 if (ret
< 0 || ret
>= MAXPATHLEN
)
770 rootfs_dir
= ovl_get_rootfs(rootfs_path
, &rootfslen
);
774 dirlen
= strlen(lxcpath
);
778 * We neither allow users to create upperdirs and workdirs outside the
779 * containerdir nor inside the rootfs. The latter might be debatable.
780 * When we have a container without a rootfs we skip the checks.
785 ret
= mkdir_p(upperdir
, 0755);
786 else if (!strncmp(upperdir
, lxcpath
, dirlen
) &&
787 strncmp(upperdir
, rootfs_dir
, rootfslen
))
788 ret
= mkdir_p(upperdir
, 0755);
791 SYSWARN("Failed to create directory \"%s\"", upperdir
);
797 ret
= mkdir_p(workdir
, 0755);
798 else if (!strncmp(workdir
, lxcpath
, dirlen
) &&
799 strncmp(workdir
, rootfs_dir
, rootfslen
))
800 ret
= mkdir_p(workdir
, 0755);
803 SYSWARN("Failed to create directory \"%s\"", workdir
);
810 lxc_free_array((void **)opts
, free
);
814 /* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
815 * with overlay lxc.mount.entry entries we need to update absolute paths for
816 * upper- and workdir. This update is done in two locations:
817 * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
818 * independent of each other since lxc_conf->mountlist may contain more mount
819 * entries (e.g. from other included files) than lxc_conf->unexpanded_config.
821 int ovl_update_abs_paths(struct lxc_conf
*lxc_conf
, const char *lxc_path
,
822 const char *lxc_name
, const char *newpath
,
825 char new_upper
[MAXPATHLEN
], new_work
[MAXPATHLEN
], old_upper
[MAXPATHLEN
],
826 old_work
[MAXPATHLEN
];
828 struct lxc_list
*iterator
;
829 char *cleanpath
= NULL
;
832 const char *ovl_dirs
[] = {"br", "upperdir", "workdir"};
834 cleanpath
= strdup(newpath
);
838 remove_trailing_slashes(cleanpath
);
841 * We have to update lxc_conf->unexpanded_config separately from
842 * lxc_conf->mount_list.
844 for (i
= 0; i
< sizeof(ovl_dirs
) / sizeof(ovl_dirs
[0]); i
++) {
845 if (!clone_update_unexp_ovl_paths(lxc_conf
, lxc_path
, newpath
,
852 snprintf(old_work
, MAXPATHLEN
, "workdir=%s/%s", lxc_path
, lxc_name
);
853 if (ret
< 0 || ret
>= MAXPATHLEN
)
857 snprintf(new_work
, MAXPATHLEN
, "workdir=%s/%s", cleanpath
, newname
);
858 if (ret
< 0 || ret
>= MAXPATHLEN
)
861 lxc_list_for_each(iterator
, &lxc_conf
->mount_list
) {
862 char *mnt_entry
= NULL
, *new_mnt_entry
= NULL
, *tmp
= NULL
,
863 *tmp_mnt_entry
= NULL
;
865 mnt_entry
= iterator
->elem
;
867 if (strstr(mnt_entry
, "overlay"))
872 ret
= snprintf(old_upper
, MAXPATHLEN
, "%s=%s/%s", tmp
, lxc_path
,
874 if (ret
< 0 || ret
>= MAXPATHLEN
)
877 ret
= snprintf(new_upper
, MAXPATHLEN
, "%s=%s/%s", tmp
,
879 if (ret
< 0 || ret
>= MAXPATHLEN
)
882 if (strstr(mnt_entry
, old_upper
)) {
884 lxc_string_replace(old_upper
, new_upper
, mnt_entry
);
887 if (strstr(mnt_entry
, old_work
)) {
889 new_mnt_entry
= lxc_string_replace(
890 old_work
, new_work
, tmp_mnt_entry
);
892 new_mnt_entry
= lxc_string_replace(
893 old_work
, new_work
, mnt_entry
);
897 free(iterator
->elem
);
898 iterator
->elem
= strdup(new_mnt_entry
);
899 } else if (tmp_mnt_entry
) {
900 free(iterator
->elem
);
901 iterator
->elem
= strdup(tmp_mnt_entry
);
914 static int ovl_remount_on_enodev(const char *lower
, const char *target
,
915 const char *name
, unsigned long mountflags
,
919 ret
= mount(lower
, target
, ovl_name
, MS_MGC_VAL
| mountflags
, options
);
920 if (ret
< 0 && errno
== ENODEV
) /* Try other module name. */
921 ret
= mount(lower
, target
,
922 ovl_name
== ovl_version
[0] ? ovl_version
[1]
924 MS_MGC_VAL
| mountflags
, options
);
928 static char *ovl_detect_name(void)
931 char *v
= ovl_version
[0];
935 f
= fopen("/proc/filesystems", "r");
939 while (getline(&line
, &len
, f
) != -1) {
940 if (strcmp(line
, "nodev\toverlayfs\n") == 0) {
951 static int ovl_do_rsync(const char *src
, const char *dest
,
952 struct lxc_conf
*conf
)
955 struct rsync_data_char rdata
= {0};
956 char cmd_output
[MAXPATHLEN
] = {0};
958 rdata
.src
= (char *)src
;
959 rdata
.dest
= (char *)dest
;
960 if (am_guest_unpriv())
961 ret
= userns_exec_full(conf
, lxc_rsync_exec_wrapper
, &rdata
,
962 "lxc_rsync_exec_wrapper");
964 ret
= run_command(cmd_output
, sizeof(cmd_output
),
965 lxc_rsync_exec_wrapper
, (void *)&rdata
);
967 ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", src
, dest
,
968 cmd_output
[0] != '\0' ? ": " : "",
969 cmd_output
[0] != '\0' ? cmd_output
: "");