[CRIU] [PATCH] fsnotify: skip non-direcory mounts

Andrew Vagin avagin at virtuozzo.com
Tue Feb 21 13:38:59 PST 2017


On Fri, Feb 17, 2017 at 05:05:45PM +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.

An error isn't a problem because we skip it and try to open via another
mount.

Can you show where it hangs for fifo?


> 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
> 
> Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
> ---
>  criu/fsnotify.c      |  4 +++-
>  criu/include/mount.h |  4 +++-
>  criu/mount.c         | 41 ++++++++++++++++++++++++++++++++++++++---
>  3 files changed, 44 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..5195c3e 100644
> --- a/criu/include/mount.h
> +++ b/criu/include/mount.h
> @@ -30,6 +30,7 @@ struct mount_info {
>  	 */
>  	char			*mountpoint;
>  	char			*ns_mountpoint;
> +	int			isdir;
>  	int			fd;
>  	unsigned		flags;
>  	unsigned		sb_flags;
> @@ -87,6 +88,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 +99,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 8f66b4e..7f0b4b0 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)
>  {
>  	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))
> +			continue;
>  		if (m->s_dev == s_dev)
>  			return m;
> +	}
>  
>  	return NULL;
>  }
> @@ -957,6 +960,38 @@ static struct mount_info *mnt_build_tree(struct mount_info *list,
>  	return tree;
>  }
>  
> +typedef enum {
> +	MNT_UNDEF	= 0,
> +	MNT_DIR		= 1,
> +	MNT_NOT_DIR	= 2,
> +} mountpoint_type;
> +
> +int notdir_mountpoint(struct mount_info *pm)
> +{
> +	int mntns_root;
> +	struct stat st;
> +
> +	if (pm->isdir == MNT_UNDEF) {
> +		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;

0 means MNT_DIR
> +		}
> +
> +		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))
> +			pm->isdir = MNT_DIR;
> +		else
> +			pm->isdir = MNT_NOT_DIR;
> +	}
> +
> +	return pm->isdir - 1;
> +}
> +
>  /*
>   * 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 +1052,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);

lookup_mnt_sdev(s_dev, MNT_DIR) - looks better

>  	if (!m)
>  		return -ENOENT;
>  
> -- 
> 2.9.3
> 


More information about the CRIU mailing list