[CRIU] [PATCH] util: use F_DUPFD when we don't want to overwrite an existing descriptor

Andrei Vagin avagin at gmail.com
Sat May 25 08:48:46 MSK 2019


Applied

On Tue, May 21, 2019 at 12:13:27AM -0700, Andrei Vagin wrote:
> Right now we use fcntl(F_GETFD) to check whether a target descriptor
> is used and then we call dup2(). Actually, we can do this for one system
> call.
> 
> Cc: Cyrill Gorcunov <gorcunov at openvz.org>
> Signed-off-by: Andrei Vagin <avagin at gmail.com>
> ---
>  criu/include/servicefd.h | 11 -----------
>  criu/servicefd.c         | 37 +++++++++++++++++++++++--------------
>  criu/util.c              | 18 +++++++++---------
>  3 files changed, 32 insertions(+), 34 deletions(-)
> 
> diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h
> index 7be472cf4..986c46af5 100644
> --- a/criu/include/servicefd.h
> +++ b/criu/include/servicefd.h
> @@ -35,17 +35,6 @@ struct pstree_item;
>  extern bool sfds_protected;
>  
>  
> -#define sfd_verify_target(_type, _old_fd, _new_fd)			\
> -	({								\
> -		int __ret = 0;						\
> -		if (fcntl(_new_fd, F_GETFD) != -1 && errno != EBADF) {	\
> -			pr_err("%s busy target %d -> %d\n",		\
> -			       sfd_type_name(_type), _old_fd, _new_fd);	\
> -			__ret = -1;					\
> -		}							\
> -		__ret;							\
> -	})
> -
>  extern const char *sfd_type_name(enum sfd_type type);
>  extern int init_service_fd(void);
>  extern int get_service_fd(enum sfd_type type);
> diff --git a/criu/servicefd.c b/criu/servicefd.c
> index 82147921c..dc423895b 100644
> --- a/criu/servicefd.c
> +++ b/criu/servicefd.c
> @@ -153,6 +153,7 @@ static void sfds_protection_bug(enum sfd_type type)
>  int install_service_fd(enum sfd_type type, int fd)
>  {
>  	int sfd = __get_service_fd(type, service_fd_id);
> +	int tmp;
>  
>  	BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX);
>  	if (sfds_protected && !test_bit(type, sfd_map))
> @@ -166,16 +167,19 @@ int install_service_fd(enum sfd_type type, int fd)
>  		return fd;
>  	}
>  
> -	if (!test_bit(type, sfd_map)) {
> -		if (sfd_verify_target(type, fd, sfd))
> -			return -1;
> -	}
> -
> -	if (dup3(fd, sfd, O_CLOEXEC) != sfd) {
> +	if (!test_bit(type, sfd_map))
> +		tmp = fcntl(fd, F_DUPFD, sfd);
> +	else
> +		tmp = dup3(fd, sfd, O_CLOEXEC);
> +	if (tmp < 0) {
>  		pr_perror("%s dup %d -> %d failed",
>  			  sfd_type_name(type), fd, sfd);
>  		close(fd);
>  		return -1;
> +	} else if (tmp != sfd) {
> +		pr_err("%s busy target %d -> %d\n", sfd_type_name(type), fd, sfd);
> +		close(fd);
> +		return -1;
>  	}
>  
>  	set_bit(type, sfd_map);
> @@ -201,25 +205,30 @@ int close_service_fd(enum sfd_type type)
>  	return 0;
>  }
>  
> -static void move_service_fd(struct pstree_item *me, int type, int new_id, int new_base)
> +static int move_service_fd(struct pstree_item *me, int type, int new_id, int new_base)
>  {
>  	int old = get_service_fd(type);
>  	int new = new_base - type - SERVICE_FD_MAX * new_id;
>  	int ret;
>  
>  	if (old < 0)
> -		return;
> +		return 0;
>  
>  	if (!test_bit(type, sfd_map))
> -		sfd_verify_target(type, old, new);
> -
> -	ret = dup2(old, new);
> +		ret = fcntl(old, F_DUPFD, new);
> +	else
> +		ret = dup2(old, new);
>  	if (ret == -1) {
> -		if (errno != EBADF)
> -			pr_perror("%s unable to clone %d->%d",
> -				  sfd_type_name(type), old, new);
> +		pr_perror("%s unable to clone %d->%d",
> +			  sfd_type_name(type), old, new);
> +		return -1;
> +	} else if (ret != new) {
> +		pr_err("%s busy target %d -> %d\n", sfd_type_name(type), old, new);
> +		return -1;
>  	} else if (!(rsti(me)->clone_flags & CLONE_FILES))
>  		close(old);
> +
> +	return 0;
>  }
>  
>  static int choose_service_fd_base(struct pstree_item *me)
> diff --git a/criu/util.c b/criu/util.c
> index 41b6915b7..8faffb859 100644
> --- a/criu/util.c
> +++ b/criu/util.c
> @@ -229,19 +229,19 @@ int reopen_fd_as_safe(char *file, int line, int new_fd, int old_fd, bool allow_r
>  	int tmp;
>  
>  	if (old_fd != new_fd) {
> -		if (!allow_reuse_fd) {
> -			if (fcntl(new_fd, F_GETFD) != -1 || errno != EBADF) {
> -				pr_err("fd %d already in use (called at %s:%d)\n",
> -					new_fd, file, line);
> -				return -1;
> -			}
> -		}
> -
> -		tmp = dup2(old_fd, new_fd);
> +		if (!allow_reuse_fd)
> +			tmp = fcntl(old_fd, F_DUPFD, new_fd);
> +		else
> +			tmp = dup2(old_fd, new_fd);
>  		if (tmp < 0) {
>  			pr_perror("Dup %d -> %d failed (called at %s:%d)",
>  				  old_fd, new_fd, file, line);
>  			return tmp;
> +		} else if (tmp != new_fd) {
> +			close(tmp);
> +			pr_err("fd %d already in use (called at %s:%d)\n",
> +				new_fd, file, line);
> +			return -1;
>  		}
>  
>  		/* Just to have error message if failed */
> -- 
> 2.20.1
> 


More information about the CRIU mailing list