Commit 6217a84a authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

mnt: Carry run-time device ID in mount_info

When we're restoring fsnotify watchees we need to resolve
path to a handle at some mountpoint referred by @s_dev
member (device ID) which is saved inside image. This
ID actually may be changed at the every mount (say
one restores container after machine reboot) or in
case of container's migration.

Thus the test for overmounting in __open_mountpoint
will fail and we get an error.

Lets do a trick: introduce @s_dev_rt member which
is supposed to carry run-time device ID. When dumping
this member simply equal to traditional @s_dev fetched
from the procfs, but when restoring we fetch it from
stat call once mountpoint become alive.

https://jira.sw.ru/browse/PSBM-41610

v2:
 - predefine MOUNT_INVALID_DEV
 - use fetch_rt_stat instead of assigning device in restore_shared_options
 - copy @s_dev_rt in propagate_siblings and propagate_mount
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 0b0f40ec
...@@ -29,10 +29,13 @@ struct ext_mount { ...@@ -29,10 +29,13 @@ struct ext_mount {
char *val; char *val;
}; };
#define MOUNT_INVALID_DEV (0)
struct mount_info { struct mount_info {
int mnt_id; int mnt_id;
int parent_mnt_id; int parent_mnt_id;
unsigned int s_dev; unsigned int s_dev;
unsigned int s_dev_rt;
char *root; char *root;
/* /*
* During dump mountpoint contains path with dot at the * During dump mountpoint contains path with dot at the
......
...@@ -1031,10 +1031,23 @@ int __open_mountpoint(struct mount_info *pm, int mnt_fd) ...@@ -1031,10 +1031,23 @@ int __open_mountpoint(struct mount_info *pm, int mnt_fd)
goto err; goto err;
} }
if (pm->s_dev_rt == MOUNT_INVALID_DEV) {
pr_err("Resolving over unvalid device for %#x %s %s\n",
pm->s_dev, pm->fstype->name, pm->ns_mountpoint);
goto err;
}
dev = phys_stat_resolve_dev(pm->nsid, st.st_dev, pm->ns_mountpoint + 1); dev = phys_stat_resolve_dev(pm->nsid, st.st_dev, pm->ns_mountpoint + 1);
if (dev != pm->s_dev) { /*
pr_err("The file system %#x (%#x) %s %s is inaccessible\n", * Always check for @s_dev_rt here, because the @s_dev
pm->s_dev, (int)dev, pm->fstype->name, pm->ns_mountpoint); * from the image (in case of restore) has all rights
* to not match the device (say it's migrated and kernel
* allocates new device ID).
*/
if (dev != pm->s_dev_rt) {
pr_err("The file system %#x %#x (%#x) %s %s is inaccessible\n",
pm->s_dev, pm->s_dev_rt, (int)dev,
pm->fstype->name, pm->ns_mountpoint);
goto err; goto err;
} }
...@@ -2102,6 +2115,7 @@ static int propagate_siblings(struct mount_info *mi) ...@@ -2102,6 +2115,7 @@ static int propagate_siblings(struct mount_info *mi)
continue; continue;
pr_debug("\t\tBind share %s\n", t->mountpoint); pr_debug("\t\tBind share %s\n", t->mountpoint);
t->bind = mi; t->bind = mi;
t->s_dev_rt = mi->s_dev_rt;
} }
list_for_each_entry(t, &mi->mnt_slave_list, mnt_slave) { list_for_each_entry(t, &mi->mnt_slave_list, mnt_slave) {
...@@ -2109,6 +2123,7 @@ static int propagate_siblings(struct mount_info *mi) ...@@ -2109,6 +2123,7 @@ static int propagate_siblings(struct mount_info *mi)
continue; continue;
pr_debug("\t\tBind slave %s\n", t->mountpoint); pr_debug("\t\tBind slave %s\n", t->mountpoint);
t->bind = mi; t->bind = mi;
t->s_dev_rt = mi->s_dev_rt;
} }
return 0; return 0;
...@@ -2154,12 +2169,26 @@ skip_parent: ...@@ -2154,12 +2169,26 @@ skip_parent:
if (t->master_id) if (t->master_id)
continue; continue;
t->bind = mi; t->bind = mi;
t->s_dev_rt = mi->s_dev_rt;
} }
} }
return 0; return 0;
} }
static int fetch_rt_stat(struct mount_info *m, const char *where)
{
struct stat st;
if (stat(where, &st)) {
pr_perror("Can't stat on %s\n", where);
return -1;
}
m->s_dev_rt = MKKDEV(major(st.st_dev), minor(st.st_dev));
return 0;
}
/* /*
* Here are a set of flags which we know how to handle for the one mount call. * Here are a set of flags which we know how to handle for the one mount call.
* All of them except MS_RDONLY are set only as mnt flags. * All of them except MS_RDONLY are set only as mnt flags.
...@@ -2383,7 +2412,7 @@ static int do_mount_root(struct mount_info *mi) ...@@ -2383,7 +2412,7 @@ static int do_mount_root(struct mount_info *mi)
mi->shared_id, mi->master_id)) mi->shared_id, mi->master_id))
return -1; return -1;
return 0; return fetch_rt_stat(mi, mi->mountpoint);
} }
static int do_mount_one(struct mount_info *mi) static int do_mount_one(struct mount_info *mi)
...@@ -2409,6 +2438,9 @@ static int do_mount_one(struct mount_info *mi) ...@@ -2409,6 +2438,9 @@ static int do_mount_one(struct mount_info *mi)
else else
ret = do_bind_mount(mi); ret = do_bind_mount(mi);
if (ret == 0 && fetch_rt_stat(mi, mi->mountpoint))
return -1;
if (ret == 0 && propagate_mount(mi)) if (ret == 0 && propagate_mount(mi))
return -1; return -1;
...@@ -2510,6 +2542,11 @@ struct mount_info *mnt_entry_alloc() ...@@ -2510,6 +2542,11 @@ struct mount_info *mnt_entry_alloc()
{ {
struct mount_info *new; struct mount_info *new;
/*
* We rely on xzalloc here for MOUNT_INVALID_DEV.
*/
BUILD_BUG_ON(MOUNT_INVALID_DEV);
new = xzalloc(sizeof(struct mount_info)); new = xzalloc(sizeof(struct mount_info));
if (new) { if (new) {
INIT_LIST_HEAD(&new->children); INIT_LIST_HEAD(&new->children);
......
...@@ -1093,7 +1093,7 @@ static int parse_mountinfo_ent(char *str, struct mount_info *new, char **fsname) ...@@ -1093,7 +1093,7 @@ static int parse_mountinfo_ent(char *str, struct mount_info *new, char **fsname)
if (!new->mountpoint) if (!new->mountpoint)
goto err; goto err;
new->s_dev = MKKDEV(kmaj, kmin); new->s_dev = new->s_dev_rt = MKKDEV(kmaj, kmin);
new->flags = 0; new->flags = 0;
if (parse_mnt_flags(opt, &new->flags)) if (parse_mnt_flags(opt, &new->flags))
goto err; goto err;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment