]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/aufs.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
29 #include <sys/types.h>
37 lxc_log_define(aufs
, lxc
);
39 /* the bulk of this needs to become a common helper */
40 extern char *dir_new_path(char *src
, const char *oldname
, const char *name
,
41 const char *oldpath
, const char *lxcpath
);
43 int lxc_rsync_delta(struct rsync_data_char
*data
)
47 ret
= lxc_switch_uid_gid(0, 0);
51 ret
= lxc_setgroups(0, NULL
);
55 ret
= lxc_rsync_exec(data
->src
, data
->dest
);
57 ERROR("Failed to rsync from \"%s\" into \"%s\"", data
->src
,
65 int lxc_rsync_delta_wrapper(void *data
)
67 struct rsync_data_char
*arg
= data
;
68 return lxc_rsync_delta(arg
);
71 int aufs_clonepaths(struct lxc_storage
*orig
, struct lxc_storage
*new,
72 const char *oldname
, const char *cname
, const char *oldpath
,
73 const char *lxcpath
, int snap
, uint64_t newsize
,
74 struct lxc_conf
*conf
)
76 char cmd_output
[MAXPATHLEN
];
79 ERROR("aufs is only for snapshot clones");
83 if (!orig
->src
|| !orig
->dest
)
86 new->dest
= dir_new_path(orig
->dest
, oldname
, cname
, oldpath
, lxcpath
);
89 if (mkdir_p(new->dest
, 0755) < 0)
92 if (am_unpriv() && chown_mapped_root(new->dest
, conf
) < 0)
93 WARN("Failed to update ownership of %s", new->dest
);
95 if (strcmp(orig
->type
, "dir") == 0) {
96 char *delta
, *lastslash
;
97 int ret
, len
, lastslashidx
;
99 // if we have /var/lib/lxc/c2/rootfs, then delta will be
100 // /var/lib/lxc/c2/delta0
101 lastslash
= strrchr(new->dest
, '/');
104 if (strlen(lastslash
) < 7)
107 lastslashidx
= lastslash
- new->dest
;
109 delta
= malloc(lastslashidx
+ 7);
112 strncpy(delta
, new->dest
, lastslashidx
+1);
113 strcpy(delta
+lastslashidx
, "delta0");
114 if ((ret
= mkdir(delta
, 0755)) < 0) {
115 SYSERROR("error: mkdir %s", delta
);
119 if (am_unpriv() && chown_mapped_root(delta
, conf
) < 0)
120 WARN("Failed to update ownership of %s", delta
);
122 // the src will be 'aufs:lowerdir:upperdir'
123 len
= strlen(delta
) + strlen(orig
->src
) + 12;
124 new->src
= malloc(len
);
129 ret
= snprintf(new->src
, len
, "aufs:%s:%s", orig
->src
, delta
);
131 if (ret
< 0 || ret
>= len
)
133 } else if (strcmp(orig
->type
, "aufs") == 0) {
134 // What exactly do we want to do here?
135 // I think we want to use the original lowerdir, with a
136 // private delta which is originally rsynced from the
138 char *osrc
, *odelta
, *nsrc
, *ndelta
;
140 if (!(osrc
= strdup(orig
->src
)))
142 nsrc
= strchr(osrc
, ':') + 1;
143 if (nsrc
!= osrc
+ 5 || (odelta
= strchr(nsrc
, ':')) == NULL
) {
149 ndelta
= dir_new_path(odelta
, oldname
, cname
, oldpath
, lxcpath
);
154 if ((ret
= mkdir(ndelta
, 0755)) < 0 && errno
!= EEXIST
) {
155 SYSERROR("error: mkdir %s", ndelta
);
160 if (am_unpriv() && chown_mapped_root(ndelta
, conf
) < 0)
161 WARN("Failed to update ownership of %s", ndelta
);
163 struct rsync_data_char rdata
;
167 ret
= userns_exec_full(conf
, lxc_rsync_delta_wrapper
,
168 &rdata
, "lxc_rsync_delta_wrapper");
170 ret
= run_command(cmd_output
, sizeof(cmd_output
),
171 lxc_rsync_delta_wrapper
,
176 ERROR("copying aufs delta");
179 len
= strlen(nsrc
) + strlen(ndelta
) + 12;
180 new->src
= malloc(len
);
186 ret
= snprintf(new->src
, len
, "aufs:%s:%s", nsrc
, ndelta
);
189 if (ret
< 0 || ret
>= len
)
192 ERROR("aufs clone of %s container is not yet supported",
194 // Note, supporting this will require aufs_mount supporting
195 // mounting of the underlay. No big deal, just needs to be done.
203 * to say 'lxc-create -t ubuntu -n o1 -B aufs' means you want
204 * $lxcpath/$lxcname/rootfs to have the created container, while all
205 * changes after starting the container are written to
206 * $lxcpath/$lxcname/delta0
208 int aufs_create(struct lxc_storage
*bdev
, const char *dest
, const char *n
,
209 struct bdev_specs
*specs
)
212 int ret
, len
= strlen(dest
), newlen
;
214 if (len
< 8 || strcmp(dest
+len
-7, "/rootfs") != 0)
217 if (!(bdev
->dest
= strdup(dest
))) {
218 ERROR("Out of memory");
222 delta
= alloca(strlen(dest
)+1);
224 strcpy(delta
+len
-6, "delta0");
226 if (mkdir_p(delta
, 0755) < 0) {
227 ERROR("Error creating %s", delta
);
231 /* aufs:lower:upper */
232 newlen
= (2 * len
) + strlen("aufs:") + 2;
233 bdev
->src
= malloc(newlen
);
235 ERROR("Out of memory");
238 ret
= snprintf(bdev
->src
, newlen
, "aufs:%s:%s", dest
, delta
);
239 if (ret
< 0 || ret
>= newlen
)
242 if (mkdir_p(bdev
->dest
, 0755) < 0) {
243 ERROR("Error creating %s", bdev
->dest
);
250 int aufs_destroy(struct lxc_storage
*orig
)
254 if (strncmp(orig
->src
, "aufs:", 5) != 0)
256 upper
= strchr(orig
->src
+ 5, ':');
260 return lxc_rmdir_onedev(upper
, NULL
);
263 bool aufs_detect(const char *path
)
265 if (!strncmp(path
, "aufs:", 5))
271 int aufs_mount(struct lxc_storage
*bdev
)
273 char *tmp
, *options
, *dup
, *lower
, *upper
;
275 unsigned long mntflags
;
278 const char *xinopath
= "/dev/shm/aufs.xino";
280 if (strcmp(bdev
->type
, "aufs"))
282 if (!bdev
->src
|| !bdev
->dest
)
285 // separately mount it first
286 // mount -t aufs -obr=${upper}=rw:${lower}=ro lower dest
287 dup
= alloca(strlen(bdev
->src
)+1);
288 strcpy(dup
, bdev
->src
);
289 /* support multiple lower layers */
290 if (!(lower
= strstr(dup
, ":/")))
294 while ((tmp
= strstr(++upper
, ":/"))) {
297 if (--upper
== lower
)
302 if (parse_mntopts(bdev
->mntopts
, &mntflags
, &mntdata
) < 0) {
307 // TODO We should check whether bdev->src is a blockdev, and if so
308 // but for now, only support aufs of a basic directory
310 // AUFS does not work on top of certain filesystems like (XFS or Btrfs)
311 // so add xino=/dev/shm/aufs.xino parameter to mount options.
312 // The same xino option can be specified to multiple aufs mounts, and
313 // a xino file is not shared among multiple aufs mounts.
315 // see http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg02587.html
316 // http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg05126.html
318 len
= strlen(lower
) + strlen(upper
) + strlen(xinopath
) + strlen("br==rw:=ro,,xino=") + strlen(mntdata
) + 1;
319 options
= alloca(len
);
320 ret
= snprintf(options
, len
, "br=%s=rw:%s=ro,%s,xino=%s", upper
, lower
, mntdata
, xinopath
);
323 len
= strlen(lower
) + strlen(upper
) + strlen(xinopath
) + strlen("br==rw:=ro,xino=") + 1;
324 options
= alloca(len
);
325 ret
= snprintf(options
, len
, "br=%s=rw:%s=ro,xino=%s", upper
, lower
, xinopath
);
328 if (ret
< 0 || ret
>= len
) {
333 ret
= mount(lower
, bdev
->dest
, "aufs", MS_MGC_VAL
| mntflags
, options
);
335 SYSERROR("aufs: error mounting %s onto %s options %s",
336 lower
, bdev
->dest
, options
);
338 INFO("aufs: mounted %s onto %s options %s",
339 lower
, bdev
->dest
, options
);
343 int aufs_umount(struct lxc_storage
*bdev
)
345 if (strcmp(bdev
->type
, "aufs"))
347 if (!bdev
->src
|| !bdev
->dest
)
349 return umount(bdev
->dest
);
352 char *aufs_get_rootfs(const char *rootfs_path
, size_t *rootfslen
)
354 char *rootfsdir
= NULL
;
359 if (!rootfs_path
|| !rootfslen
)
362 s1
= strdup(rootfs_path
);
366 if ((s2
= strstr(s1
, ":/"))) {
368 if ((s3
= strstr(s2
, ":/")))
370 rootfsdir
= strdup(s2
);
382 *rootfslen
= strlen(rootfsdir
);
387 int aufs_mkdir(const struct mntent
*mntent
, const struct lxc_rootfs
*rootfs
,
388 const char *lxc_name
, const char *lxc_path
)
390 char lxcpath
[MAXPATHLEN
];
391 char *rootfs_path
= NULL
;
392 char *rootfsdir
= NULL
;
393 char *scratch
= NULL
;
395 char *upperdir
= NULL
;
402 size_t rootfslen
= 0;
404 /* When rootfs == NULL we have a container without a rootfs. */
405 if (rootfs
&& rootfs
->path
)
406 rootfs_path
= rootfs
->path
;
408 opts
= lxc_string_split(mntent
->mnt_opts
, ',');
410 arrlen
= lxc_array_len((void **)opts
);
414 for (i
= 0; i
< arrlen
; i
++) {
415 if (strstr(opts
[i
], "br=") && (strlen(opts
[i
]) > (len
= strlen("br="))))
421 upperdir
= strtok_r(tmp
, ":=", &scratch
);
426 ret
= snprintf(lxcpath
, MAXPATHLEN
, "%s/%s", lxc_path
, lxc_name
);
427 if (ret
< 0 || ret
>= MAXPATHLEN
)
430 rootfsdir
= aufs_get_rootfs(rootfs
->path
, &rootfslen
);
436 * We neither allow users to create upperdirs and workdirs outside the
437 * containerdir nor inside the rootfs. The latter might be debatable.
438 * When we have a container without a rootfs we skip the checks.
442 ret
= mkdir_p(upperdir
, 0755);
443 else if ((strncmp(upperdir
, lxcpath
, strlen(lxcpath
)) == 0) && (strncmp(upperdir
, rootfsdir
, rootfslen
) != 0))
444 ret
= mkdir_p(upperdir
, 0755);
446 WARN("Failed to create upperdir");
452 lxc_free_array((void **)opts
, free
);