[lxc-devel] [PATCH 1/1] pivot_root: switch to a new mechanism (v2)
Stéphane Graber
stgraber at ubuntu.com
Mon Sep 22 21:22:06 UTC 2014
On Sat, Sep 20, 2014 at 03:15:44AM +0000, Serge Hallyn wrote:
> This idea came from Andy Lutomirski. Instead of using a
> temporary directory for the pivot_root put-old, use "." both
> for new-root and old-root. Then fchdir into the old root
> temporarily in order to unmount the old-root, and finally
> chdir back into our '/'.
>
> Drop lxc.pivotdir from the lxc.container.conf manpage.
>
> Warn when we see a lxc.pivotdir entry (but keep it in the
> lxc.conf for now).
>
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
Acked-by: Stéphane Graber <stgraber at ubuntu.com>
> ---
> doc/lxc.container.conf.sgml.in | 14 ---
> src/lxc/conf.c | 211 ++++++++---------------------------------
> src/lxc/confile.c | 1 +
> 3 files changed, 40 insertions(+), 186 deletions(-)
>
> diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
> index 121f882..8dbab5f 100644
> --- a/doc/lxc.container.conf.sgml.in
> +++ b/doc/lxc.container.conf.sgml.in
> @@ -943,20 +943,6 @@ proc proc proc nodev,noexec,nosuid 0 0
> </listitem>
> </varlistentry>
>
> - <varlistentry>
> - <term>
> - <option>lxc.pivotdir</option>
> - </term>
> - <listitem>
> - <para>
> - where to pivot the original root file system under
> - <option>lxc.rootfs</option>, specified relatively to
> - that. The default is <filename>mnt</filename>.
> - It is created if necessary, and also removed after
> - unmounting everything from it during container setup.
> - </para>
> - </listitem>
> - </varlistentry>
> </variablelist>
> </refsect2>
>
> diff --git a/src/lxc/conf.c b/src/lxc/conf.c
> index e61002b..31673d5 100644
> --- a/src/lxc/conf.c
> +++ b/src/lxc/conf.c
> @@ -1025,199 +1025,66 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
> return 0;
> }
>
> -static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
> -{
> - struct lxc_list *mountlist, *listentry, *iterator;
> - char *pivotdir, *mountpoint, *mountentry, *saveptr = NULL;
> - int found;
> - void **cbparm;
> -
> - mountentry = buffer;
> - cbparm = (void **)data;
> -
> - mountlist = cbparm[0];
> - pivotdir = cbparm[1];
> -
> - /* parse entry, first field is mountname, ignore */
> - mountpoint = strtok_r(mountentry, " ", &saveptr);
> - if (!mountpoint)
> - return -1;
> -
> - /* second field is mountpoint */
> - mountpoint = strtok_r(NULL, " ", &saveptr);
> - if (!mountpoint)
> - return -1;
> -
> - /* only consider mountpoints below old root fs */
> - if (strncmp(mountpoint, pivotdir, strlen(pivotdir)))
> - return 0;
> -
> - /* filter duplicate mountpoints */
> - found = 0;
> - lxc_list_for_each(iterator, mountlist) {
> - if (!strcmp(iterator->elem, mountpoint)) {
> - found = 1;
> - break;
> - }
> - }
> - if (found)
> - return 0;
> -
> - /* add entry to list */
> - listentry = malloc(sizeof(*listentry));
> - if (!listentry) {
> - SYSERROR("malloc for mountpoint listentry failed");
> - return -1;
> - }
>
> - listentry->elem = strdup(mountpoint);
> - if (!listentry->elem) {
> - SYSERROR("strdup failed");
> - free(listentry);
> - return -1;
> - }
> - lxc_list_add_tail(mountlist, listentry);
> -
> - return 0;
> -}
> -
> -static int umount_oldrootfs(const char *oldrootfs)
> +static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
> {
> - char path[MAXPATHLEN];
> - void *cbparm[2];
> - struct lxc_list mountlist, *iterator, *next;
> - int ok, still_mounted, last_still_mounted;
> - int rc;
> + int oldroot = -1, newroot = -1;
>
> - /* read and parse /proc/mounts in old root fs */
> - lxc_list_init(&mountlist);
> -
> - /* oldrootfs is on the top tree directory now */
> - rc = snprintf(path, sizeof(path), "/%s", oldrootfs);
> - if (rc >= sizeof(path)) {
> - ERROR("rootfs name too long");
> + oldroot = open("/", O_DIRECTORY | O_RDONLY);
> + if (oldroot < 0) {
> + SYSERROR("Error opening old-/ for fchdir");
> return -1;
> }
> - cbparm[0] = &mountlist;
> -
> - cbparm[1] = strdup(path);
> - if (!cbparm[1]) {
> - SYSERROR("strdup failed");
> - return -1;
> + newroot = open(rootfs, O_DIRECTORY | O_RDONLY);
> + if (newroot < 0) {
> + SYSERROR("Error opening new-/ for fchdir");
> + goto fail;
> }
>
> - rc = snprintf(path, sizeof(path), "%s/proc/mounts", oldrootfs);
> - if (rc >= sizeof(path)) {
> - ERROR("container proc/mounts name too long");
> - return -1;
> - }
> -
> - ok = lxc_file_for_each_line(path,
> - setup_rootfs_pivot_root_cb, &cbparm);
> - if (ok < 0) {
> - SYSERROR("failed to read or parse mount list '%s'", path);
> - return -1;
> - }
> -
> - /* umount filesystems until none left or list no longer shrinks */
> - still_mounted = 0;
> - do {
> - last_still_mounted = still_mounted;
> - still_mounted = 0;
> -
> - lxc_list_for_each_safe(iterator, &mountlist, next) {
> -
> - /* umount normally */
> - if (!umount(iterator->elem)) {
> - DEBUG("umounted '%s'", (char *)iterator->elem);
> - lxc_list_del(iterator);
> - continue;
> - }
> -
> - still_mounted++;
> - }
> -
> - } while (still_mounted > 0 && still_mounted != last_still_mounted);
> -
> -
> - lxc_list_for_each(iterator, &mountlist) {
> -
> - /* let's try a lazy umount */
> - if (!umount2(iterator->elem, MNT_DETACH)) {
> - INFO("lazy unmount of '%s'", (char *)iterator->elem);
> - continue;
> - }
> -
> - /* be more brutal (nfs) */
> - if (!umount2(iterator->elem, MNT_FORCE)) {
> - INFO("forced unmount of '%s'", (char *)iterator->elem);
> - continue;
> - }
> -
> - WARN("failed to unmount '%s'", (char *)iterator->elem);
> - }
> -
> - return 0;
> -}
> -
> -static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
> -{
> - char path[MAXPATHLEN];
> - int remove_pivotdir = 0;
> - int rc;
> -
> /* change into new root fs */
> - if (chdir(rootfs)) {
> + if (fchdir(newroot)) {
> SYSERROR("can't chdir to new rootfs '%s'", rootfs);
> - return -1;
> - }
> -
> - if (!pivotdir)
> - pivotdir = "lxc_putold";
> -
> - /* compute the full path to pivotdir under rootfs */
> - rc = snprintf(path, sizeof(path), "%s/%s", rootfs, pivotdir);
> - if (rc >= sizeof(path)) {
> - ERROR("pivot dir name too long");
> - return -1;
> + goto fail;
> }
>
> - if (access(path, F_OK)) {
> -
> - if (mkdir_p(path, 0755) < 0) {
> - SYSERROR("failed to create pivotdir '%s'", path);
> - return -1;
> - }
> -
> - remove_pivotdir = 1;
> - DEBUG("created '%s' directory", path);
> - }
> -
> - DEBUG("mountpoint for old rootfs is '%s'", path);
> -
> /* pivot_root into our new root fs */
> - if (pivot_root(".", path)) {
> + if (pivot_root(".", ".")) {
> SYSERROR("pivot_root syscall failed");
> - return -1;
> + goto fail;
> }
>
> - if (chdir("/")) {
> - SYSERROR("can't chdir to / after pivot_root");
> - return -1;
> + /*
> + * at this point the old-root is mounted on top of our new-root
> + * To unmounted it we must not be chdir'd into it, so escape back
> + * to old-root
> + */
> + if (fchdir(oldroot) < 0) {
> + SYSERROR("Error entering oldroot");
> + goto fail;
> + }
> + if (umount2("/", MNT_DETACH) < 0) {
> + SYSERROR("Error detaching old root");
> + goto fail;
> }
>
> - DEBUG("pivot_root syscall to '%s' successful", rootfs);
> + if (fchdir(newroot) < 0) {
> + SYSERROR("Error re-entering newroot");
> + goto fail;
> + }
>
> - /* we switch from absolute path to relative path */
> - if (umount_oldrootfs(pivotdir))
> - return -1;
> + close(oldroot);
> + close(newroot);
>
> - /* remove temporary mount point, we don't consider the removing
> - * as fatal */
> - if (remove_pivotdir && rmdir(pivotdir))
> - WARN("can't remove mountpoint '%s': %m", pivotdir);
> + DEBUG("pivot_root syscall to '%s' successful", rootfs);
>
> return 0;
> +
> +fail:
> + if (oldroot != -1)
> + close(oldroot);
> + if (newroot != -1)
> + close(newroot);
> + return -1;
> }
>
> /*
> diff --git a/src/lxc/confile.c b/src/lxc/confile.c
> index 9b1fba8..1475ac1 100644
> --- a/src/lxc/confile.c
> +++ b/src/lxc/confile.c
> @@ -1662,6 +1662,7 @@ static int config_rootfs_options(const char *key, const char *value,
> static int config_pivotdir(const char *key, const char *value,
> struct lxc_conf *lxc_conf)
> {
> + WARN("lxc.pivotdir is ignored. It will soon become an error.");
> return config_path_item(&lxc_conf->rootfs.pivot, value);
> }
>
> --
> 2.1.0
>
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
--
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140922/482147d2/attachment-0001.sig>
More information about the lxc-devel
mailing list