[CRIU] [PATCH 2/6] fdstore: add a storage for file descriptors (v2)

Andrei Vagin avagin at openvz.org
Mon Jan 9 18:00:20 PST 2017


From: Andrei Vagin <avagin at virtuozzo.com>

We need a storage for file descriptors which is shared between processes
and doesn't use a lot of file descriptors. We are going to use it on
restore and if it will use file descriptors, we will have to find
descriptors which don't used by all restored processes to not confilict
with their descriptors.

There are two solutions. The first one is a service (process) which
handles to command push_fd(id, fd) and pop_fd(id, fd).

Another solution is to save descriptros in a unix socket.  It requires
only one extra descriptor which we can register as a service fd. Each
unix socket has a buffer and can fit a number of file descriptros. We
can use SK_PEEK_OFF and MSG_PEEK to get file descriptros from a socket
as many times as we need.

This patch implements the second solution.

v2: call recvmsg with MSG_PEEK
Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
---
 criu/Makefile.crtools     |  1 +
 criu/fdstore.c            | 86 +++++++++++++++++++++++++++++++++++++++++++++++
 criu/include/fdstore.h    |  8 +++++
 criu/include/servicefd.h  |  1 +
 criu/parasite-syscall.c   |  2 +-
 include/common/scm-code.c |  4 +--
 include/common/scm.h      |  4 +--
 7 files changed, 101 insertions(+), 5 deletions(-)
 create mode 100644 criu/fdstore.c
 create mode 100644 criu/include/fdstore.h

diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools
index 8188129..b85d776 100644
--- a/criu/Makefile.crtools
+++ b/criu/Makefile.crtools
@@ -79,6 +79,7 @@ obj-y			+= uts_ns.o
 obj-y			+= path.o
 obj-y			+= autofs.o
 obj-y			+= uffd.o
+obj-y			+= fdstore.o
 
 ifeq ($(VDSO),y)
 obj-y			+= pie-util-vdso.o
diff --git a/criu/fdstore.c b/criu/fdstore.c
new file mode 100644
index 0000000..337a821
--- /dev/null
+++ b/criu/fdstore.c
@@ -0,0 +1,86 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "common/scm.h"
+#include "servicefd.h"
+#include "fdstore.h"
+#include "xmalloc.h"
+#include "log.h"
+
+static int next_id;
+
+int fdstore_init(void)
+{
+	struct sockaddr_un addr;
+	unsigned int addrlen;
+	struct stat st;
+	int sk, ret;
+
+	sk = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+	if (sk < 0) {
+		pr_perror("Unable to create a socket");
+		return -1;
+	}
+
+	if (fstat(sk, &st)) {
+		pr_perror("Unable to stat a file descriptor");
+		close(sk);
+		return -1;
+	}
+
+	addr.sun_family = AF_UNIX;
+	addrlen = snprintf(addr.sun_path, sizeof(addr.sun_path), "X/criu-fdstore-%"PRIx64, st.st_ino);
+	addrlen += sizeof(addr.sun_family);
+
+	addr.sun_path[0] = 0;
+	if (bind(sk, (struct sockaddr *) &addr, addrlen)) {
+		pr_perror("Unable to bind a socket");
+		close(sk);
+		return -1;
+	}
+	if (connect(sk, (struct sockaddr *) &addr, addrlen)) {
+		pr_perror("Unable to connect a socket");
+		close(sk);
+		return -1;
+	}
+
+	ret = install_service_fd(FDSTORE_SK_OFF, sk);
+	close(sk);
+	if (ret < 0)
+		return -1;
+
+	return 0;
+}
+
+int fdstore_add(int fd)
+{
+	int sk = get_service_fd(FDSTORE_SK_OFF);
+
+	if (send_fd(sk, NULL, 0, fd))
+		return -1;
+
+	next_id++;
+
+	return next_id - 1;
+}
+
+int fdstore_get(int id)
+{
+	int sk = get_service_fd(FDSTORE_SK_OFF);
+	int fd;
+
+	if (setsockopt(sk, SOL_SOCKET, SO_PEEK_OFF, &id, sizeof(id))) {
+		pr_perror("Unable to a peek offset");
+		return -1;
+	}
+
+	if (recv_fds(sk, &fd, 1, NULL, 0, MSG_PEEK) < 0) {
+		pr_perror("Unable to get a file descriptor with the %d id", id);
+		return -1;
+	}
+	return fd;
+}
diff --git a/criu/include/fdstore.h b/criu/include/fdstore.h
new file mode 100644
index 0000000..b406cdd
--- /dev/null
+++ b/criu/include/fdstore.h
@@ -0,0 +1,8 @@
+#ifndef __CRIU_FDSTORE_H__
+#define __CRIU_FDSTORE_H__
+
+int fdstore_init(void);
+int fdstore_add(int fd);
+int fdstore_get(int id);
+
+#endif
diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h
index 1b48e90..3e0e376 100644
--- a/criu/include/servicefd.h
+++ b/criu/include/servicefd.h
@@ -22,6 +22,7 @@ enum sfd_type {
 	TRANSPORT_FD_OFF, /* to transfer file descriptors */
 	LAZY_PAGES_SK_OFF, /* socket for communication with lazy-pages daemon */
 	RPC_SK_OFF,
+	FDSTORE_SK_OFF,
 
 	SERVICE_FD_MAX
 };
diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
index a525324..f0ff991 100644
--- a/criu/parasite-syscall.c
+++ b/criu/parasite-syscall.c
@@ -402,7 +402,7 @@ int parasite_drain_fds_seized(struct parasite_ctl *ctl,
 	}
 
 	sk = compel_rpc_sock(ctl);
-	ret = recv_fds(sk, lfds, nr_fds, opts, sizeof(struct fd_opts));
+	ret = recv_fds(sk, lfds, nr_fds, opts, sizeof(struct fd_opts), 0);
 	if (ret)
 		pr_err("Can't retrieve FDs from socket\n");
 
diff --git a/include/common/scm-code.c b/include/common/scm-code.c
index 504c972..9f21418 100644
--- a/include/common/scm-code.c
+++ b/include/common/scm-code.c
@@ -75,7 +75,7 @@ int send_fds(int sock, struct sockaddr_un *saddr, int len,
 	return 0;
 }
 
-int recv_fds(int sock, int *fds, int nr_fds, void *data, unsigned ch_size)
+int recv_fds(int sock, int *fds, int nr_fds, void *data, unsigned ch_size, int flags)
 {
 	struct scm_fdset fdset;
 	struct cmsghdr *cmsg;
@@ -88,7 +88,7 @@ int recv_fds(int sock, int *fds, int nr_fds, void *data, unsigned ch_size)
 		min_fd = min(CR_SCM_MAX_FD, nr_fds - i);
 		scm_fdset_init_chunk(&fdset, min_fd, data, ch_size);
 
-		ret = __sys(recvmsg)(sock, &fdset.hdr, 0);
+		ret = __sys(recvmsg)(sock, &fdset.hdr, flags);
 		if (ret <= 0)
 			return ret ? : -1;
 
diff --git a/include/common/scm.h b/include/common/scm.h
index 3874d1c..6110409 100644
--- a/include/common/scm.h
+++ b/include/common/scm.h
@@ -28,7 +28,7 @@ struct scm_fdset {
 extern int send_fds(int sock, struct sockaddr_un *saddr, int len,
 		int *fds, int nr_fds, void *data, unsigned ch_size);
 extern int recv_fds(int sock, int *fds, int nr_fds,
-		void *data, unsigned ch_size);
+		void *data, unsigned ch_size, int flags);
 
 static inline int send_fd(int sock, struct sockaddr_un *saddr, int saddr_len, int fd)
 {
@@ -39,7 +39,7 @@ static inline int recv_fd(int sock)
 {
 	int fd, ret;
 
-	ret = recv_fds(sock, &fd, 1, NULL, 0);
+	ret = recv_fds(sock, &fd, 1, NULL, 0, 0);
 	if (ret)
 		return -1;
 
-- 
2.7.4



More information about the CRIU mailing list