[CRIU] [PATCH 1/2] mount: Use path resolving to find mount points
Pavel Emelyanov
xemul at parallels.com
Fri Dec 6 02:39:37 PST 2013
On 12/06/2013 12:09 AM, Cyrill Gorcunov wrote:
> Instead of btrfs engine lets use path resolving feature.
> Once we find that there is some device which dev_t doesn't
> match one obtained from stat call we resolve path to a
> mountpoint and if mountpoint is laying on btrfs we use
> mount's dev_t for matching (because subvolumes may be
> not always reachable from chroot'ed environment).
>
> We use slow lookup here but it will be improved once
> all things settle down.
>
> Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
> ---
>
> Pavel, what do you think, what is the preferred way would be
> to speedup the things? Note this patch actually makes btrfs engine
> obsolete ;)
>
> files-reg.c | 2 +-
> include/mount.h | 2 +-
> mount.c | 49 ++++++++++++++++++++++++++++++++++++++++++-------
> sk-unix.c | 2 +-
> 4 files changed, 45 insertions(+), 10 deletions(-)
>
> diff --git a/files-reg.c b/files-reg.c
> index 728979d266d7..715000d06d49 100644
> --- a/files-reg.c
> +++ b/files-reg.c
> @@ -270,7 +270,7 @@ struct file_remap *lookup_ghost_remap(u32 dev, u32 ino)
>
> mutex_lock(ghost_file_mutex);
> list_for_each_entry(gf, &ghost_files, list) {
> - if (phys_stat_dev_match(gf->dev, dev) && gf->ino == ino) {
> + if (gf->ino == ino && phys_stat_dev_match(gf->dev, dev, gf->remap.path)) {
The gf->dev value came from the image. It's the device we _saw_ at dump time.
Thus we should do the name resolution _then_ and write in the image the phys
device ID instead of volume id.
> gf->remap.users++;
> mutex_unlock(ghost_file_mutex);
> return &gf->remap;
> diff --git a/include/mount.h b/include/mount.h
> index 3e4508715c79..b64673c3801d 100644
> --- a/include/mount.h
> +++ b/include/mount.h
> @@ -22,6 +22,6 @@ extern struct mount_info *lookup_mnt_sdev(unsigned int s_dev);
>
> extern struct ns_desc mnt_ns_desc;
>
> -extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev);
> +extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev, const char *path);
>
> #endif /* __CR_MOUNT_H__ */
> diff --git a/mount.c b/mount.c
> index 3c85cb036619..23d62da527e3 100644
> --- a/mount.c
> +++ b/mount.c
> @@ -98,17 +98,52 @@ struct mount_info *lookup_mnt_sdev(unsigned int s_dev)
> return NULL;
> }
>
> -bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev)
> +static struct mount_info *mount_resolve_path(const char *path)
> {
> - if (st_dev == phys_dev)
> - return true;
> + struct mount_info *m, *best = NULL, *root = NULL;
> + size_t pathlen = strlen(path);
> + size_t bestlen = PATH_MAX;
>
> /*
> - * BTRFS returns subvolume dev-id instead of
> - * superblock dev-id so we might need additional
> - * tests here.
> + * Find suitable mount point for a @path.
> + *
> + * FIXME We need some fast path resolving algorithm here.
> + * For a while stick with stupid matches.
> */
> - return is_btrfs_subvol(phys_dev, st_dev);
> + for (m = mntinfo; m; m = m->next) {
> + size_t n = strlen(m->mountpoint);
> +
> + if (!strncmp(m->mountpoint, path, min(n, pathlen))) {
> + if (bestlen > n && !is_root_mount(m)) {
> + best = m;
> + bestlen = n;
> + }
> + if (is_root_mount(m))
> + root = m;
> + }
> + }
I don't think this resolve fn is correct. You should do careful tree
descending looking at paths. Something like below.
mi = root;
sub_path = path;
next_component:
/* iterate over children mounts and find the beth path match */
list_for_each_entry(ch, &mi->children, siblings) {
len = strlen(ch->mountpoint);
if (strnel(sub_path) < len)
/* the ch point's mountpoint cannot match the subpath */
continue;
if (!strncmp(sub_path, ch->mountpoint, len) {
/* descend and search for the next mount point */
sub_path += len;
mi = ch;
goto next_component;
}
} /* no children match the path -- the current path points to mi */
return mi;
> +
> + if (!best) {
> + BUG_ON(!root);
> + best = root;
> + }
> +
> + pr_debug("Path `%s' resolved to `%s' mountpoint\n", path, best->mountpoint);
> + return best;
> +}
> +
> +bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev, const char *path)
> +{
> + struct mount_info *m;
> +
> + if (st_dev == phys_dev)
> + return true;
> +
> + m = mount_resolve_path(path);
> +
> + if (!strcmp(m->fstype->name, "btrfs"))
> + return m->s_dev == phys_dev;
> + return false;
> }
>
> /*
> diff --git a/sk-unix.c b/sk-unix.c
> index df07999d9aa9..21d2de746454 100644
> --- a/sk-unix.c
> +++ b/sk-unix.c
> @@ -355,7 +355,7 @@ static int unix_collect_one(const struct unix_diag_msg *m,
> }
>
> if ((st.st_ino != uv->udiag_vfs_ino) ||
> - !phys_stat_dev_match(st.st_dev, kdev_to_odev(uv->udiag_vfs_dev))) {
> + !phys_stat_dev_match(st.st_dev, kdev_to_odev(uv->udiag_vfs_dev), name)) {
> pr_info("unix: Dropping path %s for "
> "unlinked bound "
> "sk %#x.%#x real %#x.%#x\n",
>
More information about the CRIU
mailing list