[CRIU] [PATCH v2] fsnotify: skip non-direcory mounts
Andrew Vagin
avagin at virtuozzo.com
Fri Mar 3 10:00:23 PST 2017
On Thu, Mar 02, 2017 at 03:43:09PM +0300, Pavel Tikhomirov wrote:
> To restore fsnotify's watches on files we need to find paths for each
> of them using handle we have in /proc/<pid>/fdinfo/<fsnotifyfd>.
> These handle is valid to open the file with open_by_handle_at if
> you have mount fd where the file lays. So we try open_by_handle_at
> for all possible mount fds we have.
>
> But we can not do so for 'file' bind-mounts, as the way we open
> mount fd opens file instead and can hang on fifos or fail on sockets.
> (see check_open_handle->open_handle->open_mount code path, imagine
> lookup_mnt_sdev() found 'file' bind-mount, open_mount() failed(hanged)
> in __open_mountpoint() and if irmap_lookup() also was not successful the
> whole dump fails too)
>
> So if we have file bindmount of fifo file, and we restore some
> inotify on other file on other mount with same s_dev, we hang forever
> on open.
>
> So just skip non-directory mounts from inotify search we will find
> path for them on other mount(e.g. non-bindmount) with same s_dev.
>
> https://jira.sw.ru/browse/PSBM-57362
>
> v2: remove isdir hashing, improve commit message
> Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
> ---
> criu/fsnotify.c | 4 +++-
> criu/include/mount.h | 3 ++-
> criu/mount.c | 30 +++++++++++++++++++++++++++---
> 3 files changed, 32 insertions(+), 5 deletions(-)
>
> diff --git a/criu/fsnotify.c b/criu/fsnotify.c
> index 0dcb07c..08fd56d 100644
> --- a/criu/fsnotify.c
> +++ b/criu/fsnotify.c
> @@ -132,6 +132,8 @@ static char *alloc_openable(unsigned int s_dev, unsigned long i_ino, FhEntry *f_
>
> if (m->s_dev != s_dev)
> continue;
> + if (notdir_mountpoint(m))
> + continue;
>
> mntfd = __open_mountpoint(m, -1);
> pr_debug("\t\tTrying via mntid %d root %s ns_mountpoint @%s (%d)\n",
> @@ -238,7 +240,7 @@ int check_open_handle(unsigned int s_dev, unsigned long i_ino,
>
> pr_debug("\tHandle 0x%x:0x%lx is openable\n", s_dev, i_ino);
>
> - mi = lookup_mnt_sdev(s_dev);
> + mi = lookup_mnt_sdev(s_dev, 1);
> if (mi == NULL) {
> pr_err("Unable to lookup a mount by dev 0x%x\n", s_dev);
> goto err;
> diff --git a/criu/include/mount.h b/criu/include/mount.h
> index a692b55..9b27237 100644
> --- a/criu/include/mount.h
> +++ b/criu/include/mount.h
> @@ -87,6 +87,7 @@ extern struct ns_id *lookup_nsid_by_mnt_id(int mnt_id);
>
> extern int open_mount(unsigned int s_dev);
> extern int __open_mountpoint(struct mount_info *pm, int mnt_fd);
> +extern int notdir_mountpoint(struct mount_info *pm);
> extern int open_mountpoint(struct mount_info *pm);
>
> extern struct mount_info *collect_mntinfo(struct ns_id *ns, bool for_dump);
> @@ -97,7 +98,7 @@ extern int pivot_root(const char *new_root, const char *put_old);
> extern struct mount_info *lookup_overlayfs(char *rpath, unsigned int s_dev,
> unsigned int st_ino, unsigned int mnt_id);
> extern struct mount_info *lookup_mnt_id(unsigned int id);
> -extern struct mount_info *lookup_mnt_sdev(unsigned int s_dev);
> +extern struct mount_info *lookup_mnt_sdev(unsigned int s_dev, bool only_dir);
>
> extern dev_t phys_stat_resolve_dev(struct ns_id *, dev_t st_dev, const char *path);
> extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev,
> diff --git a/criu/mount.c b/criu/mount.c
> index 2973d27..b1a16ea 100644
> --- a/criu/mount.c
> +++ b/criu/mount.c
> @@ -223,13 +223,16 @@ struct mount_info *lookup_mnt_id(unsigned int id)
> return __lookup_mnt_id(mntinfo, id);
> }
>
> -struct mount_info *lookup_mnt_sdev(unsigned int s_dev)
> +struct mount_info *lookup_mnt_sdev(unsigned int s_dev, bool only_dir)
Nobody uses this function to open a file mounts, so I don't think that
we need this extra argument now. I suggest to add a comment why we
seatch only non-files mounts and dont' check arguments.
> {
> struct mount_info *m;
>
> - for (m = mntinfo; m != NULL; m = m->next)
> + for (m = mntinfo; m != NULL; m = m->next) {
> + if (only_dir && notdir_mountpoint(m))
this check has to be the after the next one, becase it call system
calls.
> + continue;
> if (m->s_dev == s_dev)
> return m;
> + }
>
> return NULL;
> }
> @@ -957,6 +960,27 @@ static struct mount_info *mnt_build_tree(struct mount_info *list,
> return tree;
> }
>
> +int notdir_mountpoint(struct mount_info *pm)
bool mnt_is_dir(struct mount_info *pm)
> +{
> + int mntns_root;
> + struct stat st;
> +
> + mntns_root = mntns_get_root_fd(pm->nsid);
> + if (mntns_root < 0) {
> + pr_perror("Can't get root fd of mntns for %d", pm->mnt_id);
> + return 0;
> + }
> +
> + if (fstatat(mntns_root, pm->ns_mountpoint, &st, 0)) {
> + pr_perror("Can't fstatat on %s", pm->ns_mountpoint);
> + return 0;
> + }
> +
> + if (!S_ISDIR(st.st_mode))
> + return 1;
> + return 0;
> +}
> +
> /*
> * mnt_fd is a file descriptor on the mountpoint, which is closed in an error case.
> * If mnt_fd is -1, the mountpoint will be opened by this function.
> @@ -1017,7 +1041,7 @@ int open_mount(unsigned int s_dev)
> {
> struct mount_info *m;
>
> - m = lookup_mnt_sdev(s_dev);
> + m = lookup_mnt_sdev(s_dev, 1);
> if (!m)
> return -ENOENT;
>
> --
> 2.9.3
>
More information about the CRIU
mailing list