[CRIU] [PATCH v6 7/9] unix: Add support of ghost sockets

Andrey Vagin avagin at virtuozzo.com
Tue May 22 21:36:49 MSK 2018


On Mon, May 21, 2018 at 11:05:59PM +0300, Cyrill Gorcunov wrote:
> Unix sockets may be connected via deleted socket name,
> moreover the name may be reused (ie same sun_addr but
> different inodes).
> 
> To be able to handle them we do a few tricks:
> 
>  - when collecting sockets we figure out if "deleted"
>    mark is present on the socket and if such we order
>    this sockets creation and deletion with mutex, together
>    with adding missing directories, and save this descriptors
>    in fdstore if there are peers connected to
> 
>  - on restore we connect via procfs/fd/X as suggested by
>    Andrew Vagin
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov at gmail.com>
> ---
>  criu/cr-restore.c      |   4 +
>  criu/include/sockets.h |   1 +
>  criu/sk-unix.c         | 357 +++++++++++++++++++++++++++++++++++++++++--------
>  3 files changed, 309 insertions(+), 53 deletions(-)
> 
> diff --git a/criu/cr-restore.c b/criu/cr-restore.c
> index e969c24cd1d8..645a0e724970 100644
> --- a/criu/cr-restore.c
> +++ b/criu/cr-restore.c
> @@ -384,6 +384,10 @@ static int root_prepare_shared(void)
>  	if (ret)
>  		goto err;
>  
> +	ret = unix_prepare_root_shared();
> +	if (ret)
> +		goto err;
> +
>  	ret = add_fake_unix_queuers();
>  	if (ret)
>  		goto err;
> diff --git a/criu/include/sockets.h b/criu/include/sockets.h
> index 1d0e1f29304c..f2085ace70b2 100644
> --- a/criu/include/sockets.h
> +++ b/criu/include/sockets.h
> @@ -60,6 +60,7 @@ extern int netlink_receive_one(struct nlmsghdr *hdr, struct ns_id *ns, void *arg
>  
>  extern int unix_sk_id_add(unsigned int ino);
>  extern int unix_sk_ids_parse(char *optarg);
> +extern int unix_prepare_root_shared(void);
>  
>  extern int do_dump_opt(int sk, int level, int name, void *val, int len);
>  #define dump_opt(s, l, n, f)	do_dump_opt(s, l, n, f, sizeof(*f))
> diff --git a/criu/sk-unix.c b/criu/sk-unix.c
> index 88859da02f35..c0b607d3a1d0 100644
> --- a/criu/sk-unix.c
> +++ b/criu/sk-unix.c
> @@ -9,6 +9,7 @@
>  #include <sys/un.h>
>  #include <stdlib.h>
>  #include <dlfcn.h>
> +#include <libgen.h>
>  
>  #include "libnetlink.h"
>  #include "cr_options.h"
> @@ -31,6 +32,7 @@
>  #include "fdstore.h"
>  #include "fdinfo.h"
>  #include "kerndat.h"
> +#include "rst-malloc.h"
>  
>  #include "protobuf.h"
>  #include "images/sk-unix.pb-c.h"
> @@ -89,11 +91,21 @@ struct unix_sk_desc {
>  	UnixSkEntry		*ue;
>  };
>  
> +/*
> + * The mutex_ghost is accessed from different tasks,
> + * so make sure it is in shared memory.
> + */
> +static mutex_t *mutex_ghost;
> +
>  static LIST_HEAD(unix_sockets);
> +static LIST_HEAD(unix_ghost_addr);
>  
>  static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d,
>  			     UnixSkEntry *ue, const struct fd_parms *p);
>  
> +struct unix_sk_info;
> +static int unlink_sk(struct unix_sk_info *ui);
> +
>  struct unix_sk_listen_icon {
>  	unsigned int			peer_ino;
>  	struct unix_sk_desc		*sk_desc;
> @@ -886,12 +898,15 @@ struct unix_sk_info {
>  	char			*name;
>  	char			*name_dir;
>  	unsigned		flags;
> +	int			fdstore_id;
>  	struct unix_sk_info	*peer;
>  	struct pprep_head	peer_resolve; /* XXX : union with the above? */
>  	struct file_desc	d;
>  	struct list_head	connected; /* List of sockets, connected to me */
>  	struct list_head	node; /* To link in peer's connected list  */
>  	struct list_head	scm_fles;
> +	struct list_head	ghost_node;
> +	size_t			ghost_dir_pos;
>  
>  	/*
>  	 * For DGRAM sockets with queues, we should only restore the queue
> @@ -916,6 +931,8 @@ struct scm_fle {
>  
>  #define USK_PAIR_MASTER		0x1
>  #define USK_PAIR_SLAVE		0x2
> +#define USK_GHOST_FDSTORE	0x4

pls add a comment what USK_GHOST_FDSTORE means

> +#define USK_GHOST_RENAMED	0x8
>  
>  static struct unix_sk_info *find_unix_sk_by_ino(int ino)
>  {
> @@ -1241,6 +1258,7 @@ static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd,
>  
>  static int post_open_standalone(struct file_desc *d, int fd)
>  {
> +	int fdstore_fd = -1, procfs_self_dir = -1, len;
>  	struct unix_sk_info *ui;
>  	struct unix_sk_info *peer;
>  	struct sockaddr_un addr;
........


>  static void try_resolve_unix_peer(struct unix_sk_info *ui);
> @@ -1812,6 +2007,8 @@ static int init_unix_sk_info(struct unix_sk_info *ui, UnixSkEntry *ue)
>  	ui->name_dir = (void *)ue->name_dir;
>  
>  	ui->flags		= 0;
> +	ui->fdstore_id		= -1;
> +	ui->ghost_dir_pos	= 0;
>  	ui->peer		= NULL;
>  	ui->queuer		= NULL;
>  	ui->bound		= 0;
> @@ -1826,6 +2023,51 @@ static int init_unix_sk_info(struct unix_sk_info *ui, UnixSkEntry *ue)
>  	INIT_LIST_HEAD(&ui->connected);
>  	INIT_LIST_HEAD(&ui->node);
>  	INIT_LIST_HEAD(&ui->scm_fles);
> +	INIT_LIST_HEAD(&ui->ghost_node);
> +
> +	return 0;
> +}
> +
> +int unix_prepare_root_shared(void)
> +{
> +	struct unix_sk_info *ui, *t;
> +
> +	mutex_ghost = shmalloc(sizeof(*mutex_ghost));
> +	if (!mutex_ghost) {
> +		pr_err("ghost: Can't allocate mutex\n");
> +		return -ENOMEM;
> +	}
> +	mutex_init(mutex_ghost);
> +
> +	pr_debug("ghost: Resolving addresses\n");
> +
> +	list_for_each_entry(ui, &unix_ghost_addr, ghost_node) {
> +		pr_debug("ghost: id %#x type %s state %s ino %d peer %d address %s\n",
> +			 ui->ue->id, socket_type_name(ui->ue->type),
> +			 tcp_state_name(ui->ue->state),
> +			 ui->ue->ino, ui->peer ? ui->peer->ue->ino : 0,
> +			 ui->name);
> +
> +		unlink_sk(ui);
> +
> +		/*
> +		 * Figure out who is connected to this peer,
> +		 * so the name will be removed from FS only
> +		 * when last one is connected.


is it an old comment?

> +		 */
> +		list_for_each_entry(t, &unix_sockets, list) {

Why do we need this loop
> +			if (t->flags & USK_GHOST_FDSTORE)
> +				continue;
> +			if (ui == t || t->peer != ui)
> +				continue;
> +
> +			pr_debug("\t\tghost: id %#x type %s state %s connected to us %d -> %d\n",
> +				 t->ue->id, socket_type_name(t->ue->type),
> +				 tcp_state_name(t->ue->state),
> +				 t->ue->ino, ui->ue->ino);
> +		}
> +		ui->flags |= USK_GHOST_FDSTORE;
> +	}
>  
>  	return 0;
>  }
> @@ -1873,6 +2115,15 @@ static int collect_one_unixsk(void *o, ProtobufCMessage *base, struct cr_img *i)
>  		add_post_prepare_cb(&ui->peer_resolve);
>  	}
>  
> +	if (ui->ue->deleted) {
> +		if (!ui->name || !ui->ue->name.len || !ui->name[0]) {
> +			pr_err("No name present, ino %d\n", ui->ue->ino);
> +			return -1;
> +		}
> +
> +		list_add_tail(&ui->ghost_node, &unix_ghost_addr);
> +	}
> +
>  	list_add_tail(&ui->list, &unix_sockets);
>  	return file_desc_add(&ui->d, ui->ue->id, &unix_desc_ops);
>  }
> -- 
> 2.14.3
> 


More information about the CRIU mailing list