]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/bdev/lxcoverlay.c
Split bdev into modules: lxcrsync
[mirror_lxc.git] / src / lxc / bdev / lxcoverlay.c
CommitLineData
38683db4
CB
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
8 *
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.
13 *
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.
18 *
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
22 */
23
24#define _GNU_SOURCE
25#include <errno.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include "bdev.h"
31#include "conf.h"
32#include "confile.h"
33#include "log.h"
34#include "lxccontainer.h"
3c16d0cb 35#include "lxcoverlay.h"
38683db4
CB
36#include "utils.h"
37
38lxc_log_define(overlay, lxc);
39
5c484f79
CB
40static char *ovl_name;
41
38683db4
CB
42struct ovl_rsync_data {
43 struct bdev *orig;
44 struct bdev *new;
45};
46
47/* defined in lxccontainer.c: needs to become common helper */
48extern int do_rsync(const char *src, const char *dest);
49
50/* defined in lxccontainer.c: needs to become common helper */
51extern char *dir_new_path(char *src, const char *oldname, const char *name,
52 const char *oldpath, const char *lxcpath);
53
5c484f79
CB
54static char *ovl_detect_name(void);
55static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf);
56static int ovl_rsync(struct ovl_rsync_data *data);
57static int ovl_rsync_wrapper(void *data);
38683db4 58
83e79752
CB
59int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
60 const char *cname, const char *oldpath, const char *lxcpath,
61 int snap, uint64_t newsize, struct lxc_conf *conf)
38683db4
CB
62{
63 if (!snap) {
64 ERROR("overlayfs is only for snapshot clones");
65 return -22;
66 }
67
68 if (!orig->src || !orig->dest)
69 return -1;
70
71 new->dest = dir_new_path(orig->dest, oldname, cname, oldpath, lxcpath);
72 if (!new->dest)
73 return -1;
74 if (mkdir_p(new->dest, 0755) < 0)
75 return -1;
76
77 if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
78 WARN("Failed to update ownership of %s", new->dest);
79
80 if (strcmp(orig->type, "dir") == 0) {
81 char *delta, *lastslash;
82 char *work;
83 int ret, len, lastslashidx;
84
5c484f79
CB
85 /*
86 * if we have
87 * /var/lib/lxc/c2/rootfs
88 * then delta will be
89 * /var/lib/lxc/c2/delta0
90 */
38683db4
CB
91 lastslash = strrchr(new->dest, '/');
92 if (!lastslash)
93 return -22;
94 if (strlen(lastslash) < 7)
95 return -22;
96 lastslash++;
97 lastslashidx = lastslash - new->dest;
98
99 delta = malloc(lastslashidx + 7);
100 if (!delta)
101 return -1;
5c484f79
CB
102 strncpy(delta, new->dest, lastslashidx + 1);
103 strcpy(delta + lastslashidx, "delta0");
38683db4
CB
104 if ((ret = mkdir(delta, 0755)) < 0) {
105 SYSERROR("error: mkdir %s", delta);
106 free(delta);
107 return -1;
108 }
109 if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
110 WARN("Failed to update ownership of %s", delta);
111
5c484f79
CB
112 /*
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
119 * empty.
120 */
38683db4
CB
121 work = malloc(lastslashidx + 7);
122 if (!work) {
123 free(delta);
124 return -1;
125 }
5c484f79
CB
126 strncpy(work, new->dest, lastslashidx + 1);
127 strcpy(work + lastslashidx, "olwork");
38683db4
CB
128 if (mkdir(work, 0755) < 0) {
129 SYSERROR("error: mkdir %s", work);
130 free(delta);
131 free(work);
132 return -1;
133 }
134 if (am_unpriv() && chown_mapped_root(work, conf) < 0)
135 WARN("Failed to update ownership of %s", work);
136 free(work);
137
138 // the src will be 'overlayfs:lowerdir:upperdir'
139 len = strlen(delta) + strlen(orig->src) + 12;
140 new->src = malloc(len);
141 if (!new->src) {
142 free(delta);
143 return -ENOMEM;
144 }
145 ret = snprintf(new->src, len, "overlayfs:%s:%s", orig->src, delta);
146 free(delta);
147 if (ret < 0 || ret >= len)
148 return -ENOMEM;
149 } else if (strcmp(orig->type, "overlayfs") == 0) {
5c484f79
CB
150 /*
151 * What exactly do we want to do here? I think we want to use
152 * the original lowerdir, with a private delta which is
153 * originally rsynced from the original delta
154 */
38683db4
CB
155 char *osrc, *odelta, *nsrc, *ndelta, *work;
156 char *lastslash;
157 int len, ret, lastslashidx;
158 if (!(osrc = strdup(orig->src)))
159 return -22;
160 nsrc = strchr(osrc, ':') + 1;
161 if (nsrc != osrc + 10 || (odelta = strchr(nsrc, ':')) == NULL) {
162 free(osrc);
163 return -22;
164 }
165 *odelta = '\0';
166 odelta++;
167 ndelta = dir_new_path(odelta, oldname, cname, oldpath, lxcpath);
168 if (!ndelta) {
169 free(osrc);
170 return -ENOMEM;
171 }
172 if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
173 SYSERROR("error: mkdir %s", ndelta);
174 free(osrc);
175 free(ndelta);
176 return -1;
177 }
178 if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
179 WARN("Failed to update ownership of %s", ndelta);
180
5c484f79
CB
181 /*
182 * make workdir for overlayfs.v22 or higher (see comment further
183 * up)
184 */
38683db4
CB
185 lastslash = strrchr(ndelta, '/');
186 if (!lastslash)
187 return -1;
188 lastslash++;
189 lastslashidx = lastslash - ndelta;
190
191 work = malloc(lastslashidx + 7);
192 if (!work)
193 return -1;
5c484f79
CB
194 strncpy(work, ndelta, lastslashidx + 1);
195 strcpy(work + lastslashidx, "olwork");
38683db4
CB
196 if ((mkdir(work, 0755) < 0) && errno != EEXIST) {
197 SYSERROR("error: mkdir %s", work);
198 free(work);
199 return -1;
200 }
201 if (am_unpriv() && chown_mapped_root(work, conf) < 0)
202 WARN("Failed to update ownership of %s", work);
203 free(work);
204
205 len = strlen(nsrc) + strlen(ndelta) + 12;
206 new->src = malloc(len);
207 if (!new->src) {
208 free(osrc);
209 free(ndelta);
210 return -ENOMEM;
211 }
212 ret = snprintf(new->src, len, "overlayfs:%s:%s", nsrc, ndelta);
213 free(osrc);
214 free(ndelta);
215 if (ret < 0 || ret >= len)
216 return -ENOMEM;
217
218 return ovl_do_rsync(orig, new, conf);
219 } else {
220 ERROR("overlayfs clone of %s container is not yet supported",
5c484f79
CB
221 orig->type);
222 /*
223 * Note, supporting this will require ovl_mount supporting
224 * mounting of the underlay. No big deal, just needs to be done.
225 */
38683db4
CB
226 return -1;
227 }
228
229 return 0;
230}
231
38683db4
CB
232/*
233 * to say 'lxc-create -t ubuntu -n o1 -B overlayfs' means you want
234 * $lxcpath/$lxcname/rootfs to have the created container, while all
235 * changes after starting the container are written to
236 * $lxcpath/$lxcname/delta0
237 */
83e79752 238int ovl_create(struct bdev *bdev, const char *dest, const char *n,
38683db4
CB
239 struct bdev_specs *specs)
240{
241 char *delta;
242 int ret, len = strlen(dest), newlen;
243
5c484f79 244 if (len < 8 || strcmp(dest + len - 7, "/rootfs") != 0)
38683db4
CB
245 return -1;
246
247 if (!(bdev->dest = strdup(dest))) {
248 ERROR("Out of memory");
249 return -1;
250 }
251
5c484f79 252 delta = alloca(strlen(dest) + 1);
38683db4 253 strcpy(delta, dest);
5c484f79 254 strcpy(delta + len - 6, "delta0");
38683db4
CB
255
256 if (mkdir_p(delta, 0755) < 0) {
257 ERROR("Error creating %s", delta);
258 return -1;
259 }
260
5c484f79 261 // overlayfs:lower:upper
38683db4
CB
262 newlen = (2 * len) + strlen("overlayfs:") + 2;
263 bdev->src = malloc(newlen);
264 if (!bdev->src) {
265 ERROR("Out of memory");
266 return -1;
267 }
268 ret = snprintf(bdev->src, newlen, "overlayfs:%s:%s", dest, delta);
269 if (ret < 0 || ret >= newlen)
270 return -1;
271
272 if (mkdir_p(bdev->dest, 0755) < 0) {
273 ERROR("Error creating %s", bdev->dest);
274 return -1;
275 }
276
277 return 0;
278}
279
5c484f79
CB
280int ovl_destroy(struct bdev *orig)
281{
282 char *upper;
283
284 if (strncmp(orig->src, "overlayfs:", 10) != 0)
285 return -22;
286 upper = strchr(orig->src + 10, ':');
287 if (!upper)
288 return -22;
289 upper++;
290 return lxc_rmdir_onedev(upper, NULL);
291}
292
293int ovl_detect(const char *path)
294{
295 if (strncmp(path, "overlayfs:", 10) == 0)
296 return 1; // take their word for it
297 return 0;
298}
299
300char *ovl_getlower(char *p)
301{
302 char *p1 = strchr(p, ':');
303 if (p1)
304 *p1 = '\0';
305 return p;
306}
307
308int ovl_mount(struct bdev *bdev)
309{
310 char *options, *dup, *lower, *upper;
311 char *options_work, *work, *lastslash;
312 int lastslashidx;
313 int len, len2;
314 unsigned long mntflags;
315 char *mntdata;
316 int ret, ret2;
317
318 if (strcmp(bdev->type, "overlayfs"))
319 return -22;
320 if (!bdev->src || !bdev->dest)
321 return -22;
322
323 if (!ovl_name)
324 ovl_name = ovl_detect_name();
325
326 /*
327 * separately mount it first:
328 * mount -t overlayfs * -oupperdir=${upper},lowerdir=${lower} lower dest
329 */
330 dup = alloca(strlen(bdev->src) + 1);
331 strcpy(dup, bdev->src);
332 if (!(lower = strchr(dup, ':')))
333 return -22;
334 if (!(upper = strchr(++lower, ':')))
335 return -22;
336 *upper = '\0';
337 upper++;
338
339 // if delta doesn't yet exist, create it
340 if (mkdir_p(upper, 0755) < 0 && errno != EEXIST)
341 return -22;
342
343 /*
344 * overlayfs.v22 or higher needs workdir option:
345 * if upper is
346 * /var/lib/lxc/c2/delta0
347 * then workdir is
348 * /var/lib/lxc/c2/olwork
349 */
350 lastslash = strrchr(upper, '/');
351 if (!lastslash)
352 return -22;
353 lastslash++;
354 lastslashidx = lastslash - upper;
355
356 work = alloca(lastslashidx + 7);
357 strncpy(work, upper, lastslashidx + 7);
358 strcpy(work + lastslashidx, "olwork");
359
360 if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
361 free(mntdata);
362 return -22;
363 }
364
365 if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
366 free(mntdata);
367 return -22;
368 }
369
370 /*
371 * TODO:
372 * We should check whether bdev->src is a blockdev but for now only
373 * support overlays of a basic directory
374 */
375
376 if (mntdata) {
377 len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
378 options = alloca(len);
379 ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s", upper, lower, mntdata);
380
381 len2 = strlen(lower) + strlen(upper) + strlen(work)
382 + strlen("upperdir=,lowerdir=,workdir=") + strlen(mntdata) + 1;
383 options_work = alloca(len2);
384 ret2 = snprintf(options, len2, "upperdir=%s,lowerdir=%s,workdir=%s,%s",
385 upper, lower, work, mntdata);
386 } else {
387 len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
388 options = alloca(len);
389 ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
390
391 len2 = strlen(lower) + strlen(upper) + strlen(work)
392 + strlen("upperdir=,lowerdir=,workdir=") + 1;
393 options_work = alloca(len2);
394 ret2 = snprintf(options_work, len2, "upperdir=%s,lowerdir=%s,workdir=%s",
395 upper, lower, work);
396 }
397
398 if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
399 free(mntdata);
400 return -1;
401 }
402
403 // mount without workdir option for overlayfs before v21
404 ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options);
405 if (ret < 0) {
406 INFO("overlayfs: error mounting %s onto %s options %s. retry with workdir",
407 lower, bdev->dest, options);
408
409 // retry with workdir option for overlayfs v22 and higher
410 ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options_work);
411 if (ret < 0)
412 SYSERROR("overlayfs: error mounting %s onto %s options %s",
413 lower, bdev->dest, options_work);
414 else
415 INFO("overlayfs: mounted %s onto %s options %s",
416 lower, bdev->dest, options_work);
417 } else {
418 INFO("overlayfs: mounted %s onto %s options %s",
419 lower, bdev->dest, options);
420 }
421 return ret;
422}
423
424int ovl_umount(struct bdev *bdev)
425{
426 if (strcmp(bdev->type, "overlayfs"))
427 return -22;
428 if (!bdev->src || !bdev->dest)
429 return -22;
430 return umount(bdev->dest);
431}
432
433char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen)
434{
435 char *rootfsdir = NULL;
436 char *s1 = NULL;
437 char *s2 = NULL;
438 char *s3 = NULL;
439
440 if (!rootfs_path || !rootfslen)
441 return NULL;
442
443 s1 = strdup(rootfs_path);
444 if (!s1)
445 return NULL;
446
447 if ((s2 = strstr(s1, ":/"))) {
448 s2 = s2 + 1;
449 if ((s3 = strstr(s2, ":/")))
450 *s3 = '\0';
451 rootfsdir = strdup(s2);
452 if (!rootfsdir) {
453 free(s1);
454 return NULL;
455 }
456 }
457
458 if (!rootfsdir)
459 rootfsdir = s1;
460 else
461 free(s1);
462
463 *rootfslen = strlen(rootfsdir);
464
465 return rootfsdir;
466}
467
468int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
469 const char *lxc_name, const char *lxc_path)
470{
471 char lxcpath[MAXPATHLEN];
472 char *rootfsdir = NULL;
473 char *upperdir = NULL;
474 char *workdir = NULL;
475 char **opts = NULL;
476 int fret = -1;
477 int ret = 0;
478 size_t arrlen = 0;
479 size_t dirlen = 0;
480 size_t i;
481 size_t len = 0;
482 size_t rootfslen = 0;
483
484 if (!rootfs->path || !lxc_name || !lxc_path)
485 goto err;
486
487 opts = lxc_string_split(mntent->mnt_opts, ',');
488 if (opts)
489 arrlen = lxc_array_len((void **)opts);
490 else
491 goto err;
492
493 for (i = 0; i < arrlen; i++) {
494 if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir="))))
495 upperdir = opts[i] + len;
496 else if (strstr(opts[i], "workdir=") && (strlen(opts[i]) > (len = strlen("workdir="))))
497 workdir = opts[i] + len;
498 }
499
500 ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
501 if (ret < 0 || ret >= MAXPATHLEN)
502 goto err;
503
504 rootfsdir = ovl_get_rootfs(rootfs->path, &rootfslen);
505 if (!rootfsdir)
506 goto err;
507
508 dirlen = strlen(lxcpath);
509
510 /*
511 * We neither allow users to create upperdirs and workdirs outside the
512 * containerdir nor inside the rootfs. The latter might be debatable.
513 */
514 if (upperdir)
515 if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
516 if (mkdir_p(upperdir, 0755) < 0) {
517 WARN("Failed to create upperdir");
518 }
519
520 if (workdir)
521 if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0))
522 if (mkdir_p(workdir, 0755) < 0) {
523 WARN("Failed to create workdir");
524 }
525
526 fret = 0;
527
528err:
529 free(rootfsdir);
530 lxc_free_array((void **)opts, free);
531 return fret;
532}
533
38683db4
CB
534/*
535 * To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
536 * with overlay lxc.mount.entry entries we need to update absolute paths for
537 * upper- and workdir. This update is done in two locations:
538 * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
539 * independent of each other since lxc_conf->mountlist may container more mount
540 * entries (e.g. from other included files) than lxc_conf->unexpanded_config .
541 */
83e79752
CB
542int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
543 const char *lxc_name, const char *newpath,
544 const char *newname)
38683db4
CB
545{
546 char new_upper[MAXPATHLEN];
547 char new_work[MAXPATHLEN];
548 char old_upper[MAXPATHLEN];
549 char old_work[MAXPATHLEN];
550 char *cleanpath = NULL;
551 int i;
552 int fret = -1;
553 int ret = 0;
554 struct lxc_list *iterator;
555 const char *ovl_dirs[] = {"br", "upperdir", "workdir"};
556
557 cleanpath = strdup(newpath);
558 if (!cleanpath)
559 goto err;
560
561 remove_trailing_slashes(cleanpath);
562
5c484f79
CB
563 /*
564 * We have to update lxc_conf->unexpanded_config separately from
565 * lxc_conf->mount_list.
566 */
38683db4
CB
567 for (i = 0; i < sizeof(ovl_dirs) / sizeof(ovl_dirs[0]); i++) {
568 if (!clone_update_unexp_ovl_paths(lxc_conf, lxc_path, newpath,
569 lxc_name, newname,
570 ovl_dirs[i]))
571 goto err;
572 }
573
574 ret = snprintf(old_work, MAXPATHLEN, "workdir=%s/%s", lxc_path, lxc_name);
575 if (ret < 0 || ret >= MAXPATHLEN)
576 goto err;
577
578 ret = snprintf(new_work, MAXPATHLEN, "workdir=%s/%s", cleanpath, newname);
579 if (ret < 0 || ret >= MAXPATHLEN)
580 goto err;
581
582 lxc_list_for_each(iterator, &lxc_conf->mount_list) {
583 char *mnt_entry = NULL;
584 char *new_mnt_entry = NULL;
585 char *tmp = NULL;
586 char *tmp_mnt_entry = NULL;
587 mnt_entry = iterator->elem;
588
589 if (strstr(mnt_entry, "overlay"))
590 tmp = "upperdir";
591 else if (strstr(mnt_entry, "aufs"))
592 tmp = "br";
593
594 if (!tmp)
595 continue;
596
597 ret = snprintf(old_upper, MAXPATHLEN, "%s=%s/%s", tmp, lxc_path, lxc_name);
598 if (ret < 0 || ret >= MAXPATHLEN)
599 goto err;
600
601 ret = snprintf(new_upper, MAXPATHLEN, "%s=%s/%s", tmp, cleanpath, newname);
602 if (ret < 0 || ret >= MAXPATHLEN)
603 goto err;
604
605 if (strstr(mnt_entry, old_upper)) {
606 tmp_mnt_entry = lxc_string_replace(old_upper, new_upper, mnt_entry);
607 }
608
609 if (strstr(mnt_entry, old_work)) {
610 if (tmp_mnt_entry)
611 new_mnt_entry = lxc_string_replace(old_work, new_work, tmp_mnt_entry);
612 else
613 new_mnt_entry = lxc_string_replace(old_work, new_work, mnt_entry);
614 }
615
616 if (new_mnt_entry) {
617 free(iterator->elem);
618 iterator->elem = strdup(new_mnt_entry);
619 } else if (tmp_mnt_entry) {
620 free(iterator->elem);
621 iterator->elem = strdup(tmp_mnt_entry);
622 }
623
624 free(new_mnt_entry);
625 free(tmp_mnt_entry);
626 }
627
628 fret = 0;
629err:
630 free(cleanpath);
631 return fret;
632}
633
5c484f79
CB
634static int ovl_rsync(struct ovl_rsync_data *data)
635{
636 int ret;
637
638 if (setgid(0) < 0) {
639 ERROR("Failed to setgid to 0");
640 return -1;
641 }
642 if (setgroups(0, NULL) < 0)
643 WARN("Failed to clear groups");
644 if (setuid(0) < 0) {
645 ERROR("Failed to setuid to 0");
646 return -1;
647 }
648
649 if (unshare(CLONE_NEWNS) < 0) {
650 SYSERROR("Unable to unshare mounts ns");
651 return -1;
652 }
653 if (detect_shared_rootfs()) {
654 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
655 SYSERROR("Failed to make / rslave");
656 ERROR("Continuing...");
657 }
658 }
659 if (ovl_mount(data->orig) < 0) {
660 ERROR("Failed mounting original container fs");
661 return -1;
662 }
663 if (ovl_mount(data->new) < 0) {
664 ERROR("Failed mounting new container fs");
665 return -1;
666 }
667 ret = do_rsync(data->orig->dest, data->new->dest);
668
669 ovl_umount(data->new);
670 ovl_umount(data->orig);
671
672 if (ret < 0) {
673 ERROR("rsyncing %s to %s", data->orig->dest, data->new->dest);
674 return -1;
675 }
676
677 return 0;
678}
679
680static char *ovl_detect_name(void)
681{
682 char *v = "overlayfs";
683 char *line = NULL;
684 size_t len = 0;
685 FILE *f = fopen("/proc/filesystems", "r");
686 if (!f)
687 return v;
688
689 while (getline(&line, &len, f) != -1) {
690 if (strcmp(line, "nodev\toverlay\n") == 0) {
691 v = "overlay";
692 break;
693 }
694 }
695
696 fclose(f);
697 free(line);
698 return v;
699}
700
701static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf)
702{
703 int ret = -1;
704 struct ovl_rsync_data rdata;
705
706 rdata.orig = orig;
707 rdata.new = new;
708 if (am_unpriv())
709 ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata);
710 else
711 ret = ovl_rsync(&rdata);
712 if (ret)
713 ERROR("copying overlayfs delta");
714
715 return ret;
716}
717
718static int ovl_rsync_wrapper(void *data)
719{
720 struct ovl_rsync_data *arg = data;
721 return ovl_rsync(arg);
722}
723