[CRIU] [PATCH 04/10] mounts: find mounts, which are propagated from a current one (v2)
Andrey Vagin
avagin at openvz.org
Thu Aug 29 10:54:00 EDT 2013
A few sentences, which are required for understanging this patch
2a) A shared mount can be replicated to as many mountpoints and all the
replicas continue to be exactly same.
2b) A slave mount is like a shared mount except that mount and umount
events only propagate towards it.
2c) A private mount does not forward or receive propagation.
All rules is there Documentation/filesystems/sharedsubtree.txt
If it's a first mount in a group, all group members should be
bind-mounted from this one.
Each mount propagates to all members of parent's group. The group can
contains a few slaves.
Mounts, which have propagated to slaves, are unmounted, because we can't
be sure, that they propagated in real life. For example:
mount --bind --make-slave /share /slave1
mount --bind --make-slave /share /slave2
mount /share/test
umount /slave2/test
mount --make-share /slave1/test
mount --bind --make-share /slave1/test /slave2/test
41 40 0:33 / /share rw,relatime shared:28 - tmpfs xxx rw
42 40 0:33 / /slave1 rw,relatime master:28 - tmpfs xxx rw
43 40 0:33 / /slave2 rw,relatime master:28 - tmpfs xxx rw
44 41 0:34 / /share/test rw,relatime shared:29 - tmpfs xxx rw
46 42 0:34 / /slave1/test rw,relatime shared:30 master:29 - tmpfs xxx rw
45 43 0:34 / /slave2/test rw,relatime shared:30 master:29 - tmpfs xxx rw
/slave1/test and /slave2/test depend on each other and minimum one of them
doesn't propagate from /share/test
v2: use false and true for bool
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
include/proc_parse.h | 3 ++
mount.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 112 insertions(+), 2 deletions(-)
diff --git a/include/proc_parse.h b/include/proc_parse.h
index 1a2a579..a1245cb 100644
--- a/include/proc_parse.h
+++ b/include/proc_parse.h
@@ -110,13 +110,16 @@ struct mount_info {
struct fstype *fstype;
char *source;
char *options;
+ bool mounted;
struct mount_info *next;
/* tree linkage */
struct mount_info *parent;
+ struct mount_info *bind;
struct list_head children;
struct list_head siblings;
+ struct list_head mnt_bind; /* circular list of derivatives of one real mount */
struct list_head mnt_share; /* circular list of shared mounts */
struct list_head mnt_slave_list;/* list of slave mounts */
struct list_head mnt_slave; /* slave list entry */
diff --git a/mount.c b/mount.c
index dcb30ec..ca89660 100644
--- a/mount.c
+++ b/mount.c
@@ -93,6 +93,28 @@ struct mount_info *lookup_mnt_sdev(unsigned int s_dev)
return NULL;
}
+/*
+ * Comparer two mounts. Return true if only mount points are differ.
+ * Don't care about root and mountpoints, if bind is true.
+ */
+static bool mounts_equal(struct mount_info* mi, struct mount_info *c, bool bind)
+{
+ if (mi->s_dev != c->s_dev ||
+ c->fstype != mi->fstype ||
+ strcmp(c->source, mi->source) ||
+ strcmp(c->options, mi->options))
+ return false;
+
+ if (bind)
+ return true;
+
+ if (strcmp(c->root, mi->root))
+ return false;
+ if (strcmp(basename(c->mountpoint), basename(mi->mountpoint)))
+ return false;
+ return true;
+}
+
static struct mount_info *mnt_build_ids_tree(struct mount_info *list)
{
struct mount_info *m, *root = NULL;
@@ -677,6 +699,80 @@ static char *resolve_source(struct mount_info *mi)
return NULL;
}
+/*
+ * Umount points, which are propagated in slave parents, because
+ * we can't be sure, that they were inherited in a real life.
+ */
+static int umount_from_slaves(struct mount_info *mi)
+{
+ struct mount_info *t;
+ char mpath[PATH_MAX];
+
+ list_for_each_entry(t, &mi->parent->mnt_slave_list, mnt_slave) {
+ snprintf(mpath, sizeof(mpath), "%s/%s",
+ t->mountpoint, basename(mi->mountpoint));
+ pr_debug("\t\tUmount %s\n", mpath);
+ if (umount(mpath) == -1) {
+ pr_perror("Can't umount %s", mpath);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * If something is mounted in one shared point, it will be spread in
+ * all other points from this shared group.
+ *
+ * Look at Documentation/filesystems/sharedsubtree.txt for more details
+ */
+static int propagate_siblings(struct mount_info *mi)
+{
+ struct mount_info *t;
+
+ /*
+ * Find all mounts, which must be bind-mounted from this one
+ * to inherite shared group or master id
+ */
+ list_for_each_entry(t, &mi->mnt_share, mnt_share) {
+ pr_debug("\t\tBind %s\n", t->mountpoint);
+ t->bind = mi;
+ }
+
+ list_for_each_entry(t, &mi->mnt_slave_list, mnt_slave) {
+ pr_debug("\t\tBind %s\n", t->mountpoint);
+ t->bind = mi;
+ }
+
+ return 0;
+}
+
+static int propagate_mount(struct mount_info *mi)
+{
+ struct mount_info *t;
+
+ propagate_siblings(mi);
+ umount_from_slaves(mi);
+
+ /* Propagate this mount to everyone from a parent group */
+
+ list_for_each_entry(t, &mi->parent->mnt_share, mnt_share) {
+ struct mount_info *c;
+
+ list_for_each_entry(c, &t->children, siblings) {
+ if (mounts_equal(mi, c, false)) {
+ pr_debug("\t\tPropogate %s\n", c->mountpoint);
+ c->mounted = true;
+ propagate_siblings(c);
+ umount_from_slaves(c);
+ }
+ }
+ }
+
+ return 0;
+}
+
static int do_new_mount(struct mount_info *mi)
{
char *src;
@@ -706,15 +802,25 @@ static int do_bind_mount(struct mount_info *mi)
static int do_mount_one(struct mount_info *mi)
{
+ int ret;
+
if (!mi->parent)
return 0;
+ if (mi->mounted)
+ return 0;
+
pr_debug("\tMounting %s @%s\n", mi->fstype->name, mi->mountpoint);
if (fsroot_mounted(mi))
- return do_new_mount(mi);
+ ret = do_new_mount(mi);
else
- return do_bind_mount(mi);
+ ret = do_bind_mount(mi);
+
+ if (ret == 0 && propagate_mount(mi))
+ return -1;
+
+ return ret;
}
static int do_umount_one(struct mount_info *mi)
@@ -815,6 +921,7 @@ struct mount_info *mnt_entry_alloc()
INIT_LIST_HEAD(&new->siblings);
INIT_LIST_HEAD(&new->mnt_slave_list);
INIT_LIST_HEAD(&new->mnt_share);
+ INIT_LIST_HEAD(&new->mnt_bind);
INIT_LIST_HEAD(&new->postpone);
new->mnt_master = NULL;
}
--
1.8.3.1
More information about the CRIU
mailing list