]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/overlay.c
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(struct lxc_storage
*orig
, struct lxc_storage
*new,
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
);
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 strncpy(delta
, new->dest
, lastslashidx
+ 1);
113 strncpy(delta
+ lastslashidx
, "delta0", sizeof("delta0") - 1);
114 delta
[lastslashidx
+ sizeof("delta0")] = '\0';
116 ret
= mkdir(delta
, 0755);
117 if (ret
< 0 && errno
!= EEXIST
) {
118 SYSERROR("Failed to create directory \"%s\"", delta
);
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 strncpy(work
, new->dest
, lastslashidx
+ 1);
145 strncpy(work
+ lastslashidx
, "olwork", sizeof("olwork") - 1);
146 work
[lastslashidx
+ sizeof("olwork")] = '\0';
148 if (mkdir(work
, 0755) < 0) {
149 SYSERROR("error: mkdir %s", work
);
156 ret
= chown_mapped_root(work
, conf
);
158 WARN("Failed to update ownership of %s", work
);
162 /* strlen("overlay:") = 8
172 src
= lxc_storage_get_path(orig
->src
, orig
->type
);
173 len
= 8 + strlen(delta
) + 1 + strlen(src
) + 1;
174 new->src
= malloc(len
);
176 ERROR("Failed to allocate memory");
181 ret
= snprintf(new->src
, len
, "overlay:%s:%s", src
, delta
);
183 if (ret
< 0 || (size_t)ret
>= len
) {
184 ERROR("Failed to create string");
187 } else if (!strcmp(orig
->type
, "overlayfs") ||
188 !strcmp(orig
->type
, "overlay")) {
189 char *clean_old_path
, *clean_new_path
;
190 char *lastslash
, *ndelta
, *nsrc
, *odelta
, *osrc
, *s1
, *s2
, *s3
,
192 int ret
, lastslashidx
;
193 size_t len
, name_len
;
195 osrc
= strdup(orig
->src
);
197 ERROR("Failed to duplicate string \"%s\"", orig
->src
);
201 nsrc
= strchr(osrc
, ':') + 1;
202 if ((nsrc
!= osrc
+ 8) && (nsrc
!= osrc
+ 10)) {
204 ERROR("Detected \":\" in \"%s\" at wrong position",
209 odelta
= strchr(nsrc
, ':');
212 ERROR("Failed to find \":\" in \"%s\"", nsrc
);
218 ndelta
= must_make_path(lxcpath
, cname
, "delta0", NULL
);
220 ret
= mkdir(ndelta
, 0755);
221 if (ret
< 0 && errno
!= EEXIST
) {
224 SYSERROR("Failed to create directory \"%s\"", ndelta
);
229 ret
= chown_mapped_root(ndelta
, conf
);
231 WARN("Failed to update ownership of %s",
235 /* Make workdir for overlayfs.v22 or higher (See the comment
238 lastslash
= strrchr(ndelta
, '/');
242 ERROR("Failed to detect \"/\" in \"%s\"", ndelta
);
246 lastslashidx
= lastslash
- ndelta
;
248 work
= malloc(lastslashidx
+ 7);
252 ERROR("Failed to allocate memory");
256 strncpy(work
, ndelta
, lastslashidx
+ 1);
257 strncpy(work
+ lastslashidx
, "olwork", sizeof("olwork") - 1);
258 work
[lastslashidx
+ sizeof("olwork")] = '\0';
260 ret
= mkdir(work
, 0755);
261 if (ret
< 0 && errno
!= EEXIST
) {
265 SYSERROR("Failed to create directory \"%s\"", ndelta
);
270 ret
= chown_mapped_root(work
, conf
);
272 WARN("Failed to update ownership of %s", work
);
276 /* strlen("overlay:") = 8
286 len
= 8 + strlen(ndelta
) + 1 + strlen(nsrc
) + 1;
287 new->src
= malloc(len
);
291 ERROR("Failed to allocate memory");
294 ret
= snprintf(new->src
, len
, "overlay:%s:%s", nsrc
, ndelta
);
297 if (ret
< 0 || (size_t)ret
>= len
) {
298 ERROR("Failed to create string");
302 ret
= ovl_do_rsync(orig
, new, conf
);
306 /* When we create an overlay snapshot of an overlay container in
307 * the snapshot directory under "<lxcpath>/<name>/snaps/" we
308 * don't need to record a dependency. If we would restore would
311 clean_old_path
= lxc_deslashify(oldpath
);
315 clean_new_path
= lxc_deslashify(lxcpath
);
316 if (!clean_new_path
) {
317 free(clean_old_path
);
321 s1
= strrchr(clean_old_path
, '/');
323 ERROR("Failed to detect \"/\" in string \"%s\"", s1
);
324 free(clean_old_path
);
325 free(clean_new_path
);
329 s2
= strrchr(clean_new_path
, '/');
331 ERROR("Failed to detect \"/\" in string \"%s\"", s2
);
332 free(clean_old_path
);
333 free(clean_new_path
);
337 if (!strncmp(s1
, "/snaps", sizeof("/snaps") - 1)) {
341 } else if (!strncmp(s2
, "/snaps", sizeof("/snaps") - 1)) {
344 s3
= (char *)oldname
;
346 free(clean_old_path
);
347 free(clean_new_path
);
352 if (!strncmp(s1
, s2
, len
)) {
355 tmp
= (char *)(s2
+ len
+ 1);
357 free(clean_old_path
);
358 free(clean_new_path
);
362 name_len
= strlen(s3
);
363 if (strncmp(s3
, tmp
, name_len
)) {
364 free(clean_old_path
);
365 free(clean_new_path
);
369 free(clean_old_path
);
370 free(clean_new_path
);
371 return LXC_CLONE_SNAPSHOT
;
374 free(clean_old_path
);
375 free(clean_new_path
);
378 ERROR("overlay clone of %s container is not yet supported",
380 /* Note, supporting this will require ovl_mount supporting
381 * mounting of the underlay. No big deal, just needs to be done.
389 /* To say "lxc-create -t ubuntu -n o1 -B overlay" means you want
390 * "<lxcpath>/<lxcname>/rootfs" to have the created container, while all changes
391 * after starting the container are written to "<lxcpath>/<lxcname>/delta0".
393 int ovl_create(struct lxc_storage
*bdev
, const char *dest
, const char *n
,
394 struct bdev_specs
*specs
)
401 if (len
< 8 || strcmp(dest
+ len
- 7, "/rootfs")) {
402 ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest
);
406 bdev
->dest
= strdup(dest
);
408 ERROR("Failed to duplicate string \"%s\"", dest
);
412 delta
= malloc(len
+ 1);
414 ERROR("Failed to allocate memory");
418 strncpy(delta
, dest
, len
);
419 strncpy(delta
+ len
- 6, "delta0", sizeof("delta0") - 1);
420 delta
[len
+ sizeof("delta0")] = '\0';
422 ret
= mkdir_p(delta
, 0755);
424 SYSERROR("Failed to create directory \"%s\"", delta
);
429 /* overlay:lower:upper */
430 newlen
= (2 * len
) + strlen("overlay:") + 2;
431 bdev
->src
= malloc(newlen
);
433 ERROR("Failed to allocate memory");
438 ret
= snprintf(bdev
->src
, newlen
, "overlay:%s:%s", dest
, delta
);
439 if (ret
< 0 || (size_t)ret
>= newlen
) {
440 ERROR("Failed to create string");
445 ret
= mkdir_p(bdev
->dest
, 0755);
447 SYSERROR("Failed to create directory \"%s\"", bdev
->dest
);
456 int ovl_destroy(struct lxc_storage
*orig
)
459 char *upper
= orig
->src
;
461 ovl
= !strncmp(upper
, "overlay:", 8);
462 if (!ovl
&& strncmp(upper
, "overlayfs:", 10))
470 upper
= strchr(upper
, ':');
475 return lxc_rmdir_onedev(upper
, NULL
);
478 bool ovl_detect(const char *path
)
480 if (!strncmp(path
, "overlayfs:", 10))
483 if (!strncmp(path
, "overlay:", 8))
489 int ovl_mount(struct lxc_storage
*bdev
)
491 char *tmp
, *options
, *dup
, *lower
, *upper
;
492 char *options_work
, *work
, *lastslash
;
495 unsigned long mntflags
;
499 if (strcmp(bdev
->type
, "overlay") && strcmp(bdev
->type
, "overlayfs"))
502 if (!bdev
->src
|| !bdev
->dest
)
506 ovl_name
= ovl_detect_name();
508 /* Separately mount it first:
509 * mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
511 dup
= strdup(bdev
->src
);
513 ERROR("Failed to allocate memory");
517 /* support multiple lower layers */
518 lower
= strstr(dup
, ":/");
520 ERROR("Failed to detect \":/\" in string \"%s\"", dup
);
527 while ((tmp
= strstr(++upper
, ":/"))) {
532 if (upper
== lower
) {
539 /* if delta doesn't yet exist, create it */
540 ret
= mkdir_p(upper
, 0755) < 0;
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 strncpy(work
, upper
, lastslashidx
+ 1);
571 strncpy(work
+ lastslashidx
, "olwork", sizeof("olwork") - 1);
572 work
[lastslashidx
+ sizeof("olwork")] = '\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 char *ovl_get_lower(const char *rootfs_path
)
687 s1
= strstr(rootfs_path
, ":/");
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
);
714 s2
= strstr(s1
, ":/");
717 if ((s3
= strstr(s2
, ":/")))
719 rootfsdir
= strdup(s2
);
731 *rootfslen
= strlen(rootfsdir
);
736 int ovl_mkdir(const struct mntent
*mntent
, const struct lxc_rootfs
*rootfs
,
737 const char *lxc_name
, const char *lxc_path
)
739 char lxcpath
[MAXPATHLEN
];
742 size_t arrlen
, dirlen
, i
, len
, rootfslen
;
744 char *rootfs_dir
= NULL
, *rootfs_path
= NULL
, *upperdir
= NULL
,
747 /* When rootfs == NULL we have a container without a rootfs. */
748 if (rootfs
&& rootfs
->path
)
749 rootfs_path
= rootfs
->path
;
751 opts
= lxc_string_split(mntent
->mnt_opts
, ',');
753 arrlen
= lxc_array_len((void **)opts
);
757 for (i
= 0; i
< arrlen
; i
++) {
758 if (strstr(opts
[i
], "upperdir=") &&
759 (strlen(opts
[i
]) > (len
= strlen("upperdir="))))
760 upperdir
= opts
[i
] + len
;
761 else if (strstr(opts
[i
], "workdir=") &&
762 (strlen(opts
[i
]) > (len
= strlen("workdir="))))
763 workdir
= opts
[i
] + len
;
768 snprintf(lxcpath
, MAXPATHLEN
, "%s/%s", lxc_path
, lxc_name
);
769 if (ret
< 0 || ret
>= MAXPATHLEN
)
772 rootfs_dir
= ovl_get_rootfs(rootfs_path
, &rootfslen
);
776 dirlen
= strlen(lxcpath
);
780 * We neither allow users to create upperdirs and workdirs outside the
781 * containerdir nor inside the rootfs. The latter might be debatable.
782 * When we have a container without a rootfs we skip the checks.
787 ret
= mkdir_p(upperdir
, 0755);
788 else if (!strncmp(upperdir
, lxcpath
, dirlen
) &&
789 strncmp(upperdir
, rootfs_dir
, rootfslen
))
790 ret
= mkdir_p(upperdir
, 0755);
792 WARN("Failed to create directory \"%s\": %s", upperdir
,
799 ret
= mkdir_p(workdir
, 0755);
800 else if (!strncmp(workdir
, lxcpath
, dirlen
) &&
801 strncmp(workdir
, rootfs_dir
, rootfslen
))
802 ret
= mkdir_p(workdir
, 0755);
804 WARN("Failed to create directory \"%s\": %s", workdir
,
812 lxc_free_array((void **)opts
, free
);
816 /* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
817 * with overlay lxc.mount.entry entries we need to update absolute paths for
818 * upper- and workdir. This update is done in two locations:
819 * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
820 * independent of each other since lxc_conf->mountlist may contain more mount
821 * entries (e.g. from other included files) than lxc_conf->unexpanded_config.
823 int ovl_update_abs_paths(struct lxc_conf
*lxc_conf
, const char *lxc_path
,
824 const char *lxc_name
, const char *newpath
,
827 char new_upper
[MAXPATHLEN
], new_work
[MAXPATHLEN
], old_upper
[MAXPATHLEN
],
828 old_work
[MAXPATHLEN
];
830 struct lxc_list
*iterator
;
831 char *cleanpath
= NULL
;
834 const char *ovl_dirs
[] = {"br", "upperdir", "workdir"};
836 cleanpath
= strdup(newpath
);
840 remove_trailing_slashes(cleanpath
);
843 * We have to update lxc_conf->unexpanded_config separately from
844 * lxc_conf->mount_list.
846 for (i
= 0; i
< sizeof(ovl_dirs
) / sizeof(ovl_dirs
[0]); i
++) {
847 if (!clone_update_unexp_ovl_paths(lxc_conf
, lxc_path
, newpath
,
854 snprintf(old_work
, MAXPATHLEN
, "workdir=%s/%s", lxc_path
, lxc_name
);
855 if (ret
< 0 || ret
>= MAXPATHLEN
)
859 snprintf(new_work
, MAXPATHLEN
, "workdir=%s/%s", cleanpath
, newname
);
860 if (ret
< 0 || ret
>= MAXPATHLEN
)
863 lxc_list_for_each(iterator
, &lxc_conf
->mount_list
) {
864 char *mnt_entry
= NULL
, *new_mnt_entry
= NULL
, *tmp
= NULL
,
865 *tmp_mnt_entry
= NULL
;
867 mnt_entry
= iterator
->elem
;
869 if (strstr(mnt_entry
, "overlay"))
871 else if (strstr(mnt_entry
, "aufs"))
877 ret
= snprintf(old_upper
, MAXPATHLEN
, "%s=%s/%s", tmp
, lxc_path
,
879 if (ret
< 0 || ret
>= MAXPATHLEN
)
882 ret
= snprintf(new_upper
, MAXPATHLEN
, "%s=%s/%s", tmp
,
884 if (ret
< 0 || ret
>= MAXPATHLEN
)
887 if (strstr(mnt_entry
, old_upper
)) {
889 lxc_string_replace(old_upper
, new_upper
, mnt_entry
);
892 if (strstr(mnt_entry
, old_work
)) {
894 new_mnt_entry
= lxc_string_replace(
895 old_work
, new_work
, tmp_mnt_entry
);
897 new_mnt_entry
= lxc_string_replace(
898 old_work
, new_work
, mnt_entry
);
902 free(iterator
->elem
);
903 iterator
->elem
= strdup(new_mnt_entry
);
904 } else if (tmp_mnt_entry
) {
905 free(iterator
->elem
);
906 iterator
->elem
= strdup(tmp_mnt_entry
);
919 static int ovl_remount_on_enodev(const char *lower
, const char *target
,
920 const char *name
, unsigned long mountflags
,
924 ret
= mount(lower
, target
, ovl_name
, MS_MGC_VAL
| mountflags
, options
);
925 if (ret
< 0 && errno
== ENODEV
) /* Try other module name. */
926 ret
= mount(lower
, target
,
927 ovl_name
== ovl_version
[0] ? ovl_version
[1]
929 MS_MGC_VAL
| mountflags
, options
);
933 static char *ovl_detect_name(void)
936 char *v
= ovl_version
[0];
940 f
= fopen("/proc/filesystems", "r");
944 while (getline(&line
, &len
, f
) != -1) {
945 if (strcmp(line
, "nodev\toverlayfs\n") == 0) {
956 static int ovl_do_rsync(struct lxc_storage
*orig
, struct lxc_storage
*new,
957 struct lxc_conf
*conf
)
960 struct rsync_data rdata
= {0, 0};
961 char cmd_output
[MAXPATHLEN
] = {0};
966 ret
= userns_exec_1(conf
, lxc_rsync_exec_wrapper
, &rdata
,
967 "lxc_rsync_exec_wrapper");
969 ERROR("Failed to rsync from \"%s\" into \"%s\"",
970 orig
->dest
, new->dest
);
972 ret
= run_command(cmd_output
, sizeof(cmd_output
),
973 lxc_rsync_exec_wrapper
, (void *)&rdata
);
975 ERROR("Failed to rsync from \"%s\" into \"%s\": %s",
976 orig
->dest
, new->dest
, cmd_output
);