]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/overlay.c
7a41c0b85e847c30b7588d877e53c5bc10919184
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 *osrc
, *odelta
, *nsrc
, *ndelta
, *work
;
191 int ret
, lastslashidx
;
194 osrc
= strdup(orig
->src
);
196 ERROR("Failed to duplicate string \"%s\"", orig
->src
);
200 nsrc
= strchr(osrc
, ':') + 1;
201 if ((nsrc
!= osrc
+ 8) && (nsrc
!= osrc
+ 10)) {
203 ERROR("Detected \":\" in \"%s\" at wrong position",
208 odelta
= strchr(nsrc
, ':');
211 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
) {
223 SYSERROR("Failed to create directory \"%s\"", ndelta
);
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
, '/');
241 ERROR("Failed to detect \"/\" in \"%s\"", ndelta
);
245 lastslashidx
= lastslash
- ndelta
;
247 work
= malloc(lastslashidx
+ 7);
251 ERROR("Failed to allocate memory");
255 strncpy(work
, ndelta
, lastslashidx
+ 1);
256 strncpy(work
+ lastslashidx
, "olwork", sizeof("olwork") - 1);
257 work
[lastslashidx
+ sizeof("olwork")] = '\0';
259 ret
= mkdir(work
, 0755);
260 if (ret
< 0 && errno
!= EEXIST
) {
264 SYSERROR("Failed to create directory \"%s\"", ndelta
);
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
);
296 if (ret
< 0 || (size_t)ret
>= len
) {
297 ERROR("Failed to create string");
301 return ovl_do_rsync(orig
, new, conf
);
303 ERROR("overlay clone of %s container is not yet supported",
305 /* Note, supporting this will require ovl_mount supporting
306 * mounting of the underlay. No big deal, just needs to be done.
314 /* To say "lxc-create -t ubuntu -n o1 -B overlay" means you want
315 * "<lxcpath>/<lxcname>/rootfs" to have the created container, while all changes
316 * after starting the container are written to "<lxcpath>/<lxcname>/delta0".
318 int ovl_create(struct lxc_storage
*bdev
, const char *dest
, const char *n
,
319 struct bdev_specs
*specs
)
326 if (len
< 8 || strcmp(dest
+ len
- 7, "/rootfs")) {
327 ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest
);
331 bdev
->dest
= strdup(dest
);
333 ERROR("Failed to duplicate string \"%s\"", dest
);
337 delta
= malloc(len
+ 1);
339 ERROR("Failed to allocate memory");
343 strncpy(delta
, dest
, len
);
344 strncpy(delta
+ len
- 6, "delta0", sizeof("delta0") - 1);
345 delta
[len
+ sizeof("delta0")] = '\0';
347 ret
= mkdir_p(delta
, 0755);
349 SYSERROR("Failed to create directory \"%s\"", delta
);
354 /* overlay:lower:upper */
355 newlen
= (2 * len
) + strlen("overlay:") + 2;
356 bdev
->src
= malloc(newlen
);
358 ERROR("Failed to allocate memory");
363 ret
= snprintf(bdev
->src
, newlen
, "overlay:%s:%s", dest
, delta
);
364 if (ret
< 0 || (size_t)ret
>= newlen
) {
365 ERROR("Failed to create string");
370 ret
= mkdir_p(bdev
->dest
, 0755);
372 SYSERROR("Failed to create directory \"%s\"", bdev
->dest
);
381 int ovl_destroy(struct lxc_storage
*orig
)
384 char *upper
= orig
->src
;
386 ovl
= !strncmp(upper
, "overlay:", 8);
387 if (!ovl
&& strncmp(upper
, "overlayfs:", 10))
395 upper
= strchr(upper
, ':');
400 return lxc_rmdir_onedev(upper
, NULL
);
403 bool ovl_detect(const char *path
)
405 if (!strncmp(path
, "overlayfs:", 10))
408 if (!strncmp(path
, "overlay:", 8))
414 int ovl_mount(struct lxc_storage
*bdev
)
416 char *tmp
, *options
, *dup
, *lower
, *upper
;
417 char *options_work
, *work
, *lastslash
;
420 unsigned long mntflags
;
424 if (strcmp(bdev
->type
, "overlay") && strcmp(bdev
->type
, "overlayfs"))
427 if (!bdev
->src
|| !bdev
->dest
)
431 ovl_name
= ovl_detect_name();
433 /* Separately mount it first:
434 * mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
436 dup
= strdup(bdev
->src
);
438 ERROR("Failed to allocate memory");
442 /* support multiple lower layers */
443 lower
= strstr(dup
, ":/");
445 ERROR("Failed to detect \":/\" in string \"%s\"", dup
);
452 while ((tmp
= strstr(++upper
, ":/"))) {
457 if (upper
== lower
) {
464 /* if delta doesn't yet exist, create it */
465 ret
= mkdir_p(upper
, 0755) < 0;
466 if (ret
< 0 && errno
!= EEXIST
) {
467 SYSERROR("Failed to create directory \"%s\"", upper
);
472 /* overlayfs.v22 or higher needs workdir option:
474 * /var/lib/lxc/c2/delta0
476 * /var/lib/lxc/c2/olwork
478 lastslash
= strrchr(upper
, '/');
480 ERROR("Failed to detect \"/\" in string \"%s\"", upper
);
486 lastslashidx
= lastslash
- upper
;
488 work
= malloc(lastslashidx
+ 7);
490 ERROR("Failed to allocate memory");
495 strncpy(work
, upper
, lastslashidx
+ 1);
496 strncpy(work
+ lastslashidx
, "olwork", sizeof("olwork") - 1);
497 work
[lastslashidx
+ sizeof("olwork")] = '\0';
499 ret
= parse_mntopts(bdev
->mntopts
, &mntflags
, &mntdata
);
501 ERROR("Failed to parse mount options");
508 ret
= mkdir_p(work
, 0755);
509 if (ret
< 0 && errno
!= EEXIST
) {
510 SYSERROR("Failed to create directory \"%s\"", work
);
519 * We should check whether bdev->src is a blockdev but for now only
520 * support overlays of a basic directory
524 len
= strlen(lower
) + strlen(upper
) +
525 strlen("upperdir=,lowerdir=,") + strlen(mntdata
) + 1;
526 options
= alloca(len
);
527 ret
= snprintf(options
, len
, "upperdir=%s,lowerdir=%s,%s",
528 upper
, lower
, mntdata
);
530 len2
= strlen(lower
) + strlen(upper
) + strlen(work
) +
531 strlen("upperdir=,lowerdir=,workdir=") +
533 options_work
= alloca(len2
);
534 ret2
= snprintf(options
, len2
,
535 "upperdir=%s,lowerdir=%s,workdir=%s,%s", upper
,
536 lower
, work
, mntdata
);
538 len
= strlen(lower
) + strlen(upper
) +
539 strlen("upperdir=,lowerdir=") + 1;
540 options
= alloca(len
);
541 ret
= snprintf(options
, len
, "upperdir=%s,lowerdir=%s", upper
,
544 len2
= strlen(lower
) + strlen(upper
) + strlen(work
) +
545 strlen("upperdir=,lowerdir=,workdir=") + 1;
546 options_work
= alloca(len2
);
547 ret2
= snprintf(options_work
, len2
,
548 "upperdir=%s,lowerdir=%s,workdir=%s", upper
,
552 if (ret
< 0 || ret
>= len
|| ret2
< 0 || ret2
>= len2
) {
553 ERROR("Failed to create string");
560 /* Assume we need a workdir as we are on a overlay version >= v22. */
561 ret
= ovl_remount_on_enodev(lower
, bdev
->dest
, ovl_name
,
562 MS_MGC_VAL
| mntflags
, options_work
);
564 INFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". "
565 "Retrying without workdir: %s",
566 lower
, bdev
->dest
, options_work
, strerror(errno
));
568 /* Assume we cannot use a workdir as we are on a version <= v21.
570 ret
= ovl_remount_on_enodev(lower
, bdev
->dest
, ovl_name
,
571 MS_MGC_VAL
| mntflags
, options
);
573 SYSERROR("Failed to mount \"%s\" on \"%s\" with "
574 "options \"%s\": %s",
575 lower
, bdev
->dest
, options
, strerror(errno
));
577 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"",
578 lower
, bdev
->dest
, options
);
580 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower
,
581 bdev
->dest
, options_work
);
589 int ovl_umount(struct lxc_storage
*bdev
)
593 if (strcmp(bdev
->type
, "overlay") && strcmp(bdev
->type
, "overlayfs"))
596 if (!bdev
->src
|| !bdev
->dest
)
599 ret
= umount(bdev
->dest
);
601 SYSERROR("Failed to unmount \"%s\"", bdev
->dest
);
603 TRACE("Unmounted \"%s\"", bdev
->dest
);
608 char *ovl_get_lower(const char *rootfs_path
)
612 s1
= strstr(rootfs_path
, ":/");
617 s1
= strstr(s1
, ":/");
625 char *ovl_get_rootfs(const char *rootfs_path
, size_t *rootfslen
)
627 char *rootfsdir
= NULL
;
632 if (!rootfs_path
|| !rootfslen
)
635 s1
= strdup(rootfs_path
);
639 s2
= strstr(s1
, ":/");
642 if ((s3
= strstr(s2
, ":/")))
644 rootfsdir
= strdup(s2
);
656 *rootfslen
= strlen(rootfsdir
);
661 int ovl_mkdir(const struct mntent
*mntent
, const struct lxc_rootfs
*rootfs
,
662 const char *lxc_name
, const char *lxc_path
)
664 char lxcpath
[MAXPATHLEN
];
667 size_t arrlen
, dirlen
, i
, len
, rootfslen
;
669 char *rootfs_dir
= NULL
, *rootfs_path
= NULL
, *upperdir
= NULL
,
672 /* When rootfs == NULL we have a container without a rootfs. */
673 if (rootfs
&& rootfs
->path
)
674 rootfs_path
= rootfs
->path
;
676 opts
= lxc_string_split(mntent
->mnt_opts
, ',');
678 arrlen
= lxc_array_len((void **)opts
);
682 for (i
= 0; i
< arrlen
; i
++) {
683 if (strstr(opts
[i
], "upperdir=") &&
684 (strlen(opts
[i
]) > (len
= strlen("upperdir="))))
685 upperdir
= opts
[i
] + len
;
686 else if (strstr(opts
[i
], "workdir=") &&
687 (strlen(opts
[i
]) > (len
= strlen("workdir="))))
688 workdir
= opts
[i
] + len
;
693 snprintf(lxcpath
, MAXPATHLEN
, "%s/%s", lxc_path
, lxc_name
);
694 if (ret
< 0 || ret
>= MAXPATHLEN
)
697 rootfs_dir
= ovl_get_rootfs(rootfs_path
, &rootfslen
);
701 dirlen
= strlen(lxcpath
);
705 * We neither allow users to create upperdirs and workdirs outside the
706 * containerdir nor inside the rootfs. The latter might be debatable.
707 * When we have a container without a rootfs we skip the checks.
712 ret
= mkdir_p(upperdir
, 0755);
713 else if (!strncmp(upperdir
, lxcpath
, dirlen
) &&
714 strncmp(upperdir
, rootfs_dir
, rootfslen
))
715 ret
= mkdir_p(upperdir
, 0755);
717 WARN("Failed to create directory \"%s\": %s", upperdir
,
724 ret
= mkdir_p(workdir
, 0755);
725 else if (!strncmp(workdir
, lxcpath
, dirlen
) &&
726 strncmp(workdir
, rootfs_dir
, rootfslen
))
727 ret
= mkdir_p(workdir
, 0755);
729 WARN("Failed to create directory \"%s\": %s", workdir
,
737 lxc_free_array((void **)opts
, free
);
741 /* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
742 * with overlay lxc.mount.entry entries we need to update absolute paths for
743 * upper- and workdir. This update is done in two locations:
744 * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
745 * independent of each other since lxc_conf->mountlist may contain more mount
746 * entries (e.g. from other included files) than lxc_conf->unexpanded_config.
748 int ovl_update_abs_paths(struct lxc_conf
*lxc_conf
, const char *lxc_path
,
749 const char *lxc_name
, const char *newpath
,
752 char new_upper
[MAXPATHLEN
], new_work
[MAXPATHLEN
], old_upper
[MAXPATHLEN
],
753 old_work
[MAXPATHLEN
];
755 struct lxc_list
*iterator
;
756 char *cleanpath
= NULL
;
759 const char *ovl_dirs
[] = {"br", "upperdir", "workdir"};
761 cleanpath
= strdup(newpath
);
765 remove_trailing_slashes(cleanpath
);
768 * We have to update lxc_conf->unexpanded_config separately from
769 * lxc_conf->mount_list.
771 for (i
= 0; i
< sizeof(ovl_dirs
) / sizeof(ovl_dirs
[0]); i
++) {
772 if (!clone_update_unexp_ovl_paths(lxc_conf
, lxc_path
, newpath
,
779 snprintf(old_work
, MAXPATHLEN
, "workdir=%s/%s", lxc_path
, lxc_name
);
780 if (ret
< 0 || ret
>= MAXPATHLEN
)
784 snprintf(new_work
, MAXPATHLEN
, "workdir=%s/%s", cleanpath
, newname
);
785 if (ret
< 0 || ret
>= MAXPATHLEN
)
788 lxc_list_for_each(iterator
, &lxc_conf
->mount_list
) {
789 char *mnt_entry
= NULL
, *new_mnt_entry
= NULL
, *tmp
= NULL
,
790 *tmp_mnt_entry
= NULL
;
792 mnt_entry
= iterator
->elem
;
794 if (strstr(mnt_entry
, "overlay"))
796 else if (strstr(mnt_entry
, "aufs"))
802 ret
= snprintf(old_upper
, MAXPATHLEN
, "%s=%s/%s", tmp
, lxc_path
,
804 if (ret
< 0 || ret
>= MAXPATHLEN
)
807 ret
= snprintf(new_upper
, MAXPATHLEN
, "%s=%s/%s", tmp
,
809 if (ret
< 0 || ret
>= MAXPATHLEN
)
812 if (strstr(mnt_entry
, old_upper
)) {
814 lxc_string_replace(old_upper
, new_upper
, mnt_entry
);
817 if (strstr(mnt_entry
, old_work
)) {
819 new_mnt_entry
= lxc_string_replace(
820 old_work
, new_work
, tmp_mnt_entry
);
822 new_mnt_entry
= lxc_string_replace(
823 old_work
, new_work
, mnt_entry
);
827 free(iterator
->elem
);
828 iterator
->elem
= strdup(new_mnt_entry
);
829 } else if (tmp_mnt_entry
) {
830 free(iterator
->elem
);
831 iterator
->elem
= strdup(tmp_mnt_entry
);
844 static int ovl_remount_on_enodev(const char *lower
, const char *target
,
845 const char *name
, unsigned long mountflags
,
849 ret
= mount(lower
, target
, ovl_name
, MS_MGC_VAL
| mountflags
, options
);
850 if (ret
< 0 && errno
== ENODEV
) /* Try other module name. */
851 ret
= mount(lower
, target
,
852 ovl_name
== ovl_version
[0] ? ovl_version
[1]
854 MS_MGC_VAL
| mountflags
, options
);
858 static char *ovl_detect_name(void)
861 char *v
= ovl_version
[0];
865 f
= fopen("/proc/filesystems", "r");
869 while (getline(&line
, &len
, f
) != -1) {
870 if (strcmp(line
, "nodev\toverlayfs\n") == 0) {
881 static int ovl_do_rsync(struct lxc_storage
*orig
, struct lxc_storage
*new,
882 struct lxc_conf
*conf
)
885 struct rsync_data rdata
= {0, 0};
886 char cmd_output
[MAXPATHLEN
] = {0};
891 ret
= userns_exec_1(conf
, lxc_rsync_exec_wrapper
, &rdata
,
892 "lxc_rsync_exec_wrapper");
894 ERROR("Failed to rsync from \"%s\" into \"%s\"",
895 orig
->dest
, new->dest
);
897 ret
= run_command(cmd_output
, sizeof(cmd_output
),
898 lxc_rsync_exec_wrapper
, (void *)&rdata
);
900 ERROR("Failed to rsync from \"%s\" into \"%s\": %s",
901 orig
->dest
, new->dest
, cmd_output
);