[CRIU] [PATCH v2 12/15] unix: Send senders fds of packets in receive queue to receiver
Kirill Tkhai
ktkhai at virtuozzo.com
Fri May 27 06:07:35 PDT 2016
Promiscuous receive queues should be restored by the queue owner,
since there is no a existing queuer for it.
This patch makes a socket, who have sent a packet to a promiscous
queue, send its file descriptor to the queue's owner. Promiscous
sockets, who want its fd, after previous patches are already linked
in unix_sk_info::receivers list.
Promiscous queue's owner receive the fds in receive_unix_sk() and
store them in unix_sk_info::foreign_fds massive.
To receive a sender, transport socket must be dupped. We do that
to free a fd, which is used for real socket we open.
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
criu/sk-unix.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 128 insertions(+), 7 deletions(-)
diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index fc3cb44..c14c8c4 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -833,7 +833,10 @@ int fix_external_unix_sockets(void)
struct unix_sk_info {
UnixSkEntry *ue;
struct list_head list;
- struct list_head receivers;
+ union {
+ struct list_head receivers;
+ int *foreign_fds;
+ };
char *name;
char *name_dir;
unsigned flags;
@@ -855,6 +858,7 @@ struct unix_sk_info {
u32 queuer;
u32 nr_senders;
+ int transport_fd;
};
#define USK_PAIR_MASTER 0x1
@@ -1052,7 +1056,7 @@ static int unixsk_should_open_transport(FdinfoEntry *fe,
struct unix_sk_info *ui;
ui = container_of(d, struct unix_sk_info, d);
- return ui->flags & USK_PAIR_SLAVE;
+ return (ui->flags & USK_PAIR_SLAVE) || ui->nr_senders;
}
static int open_unixsk_pair_master(struct unix_sk_info *ui)
@@ -1142,6 +1146,8 @@ static int open_unixsk_pair_slave(struct unix_sk_info *ui)
static int open_unixsk_standalone(struct unix_sk_info *ui)
{
+ struct fdinfo_list_entry *fle;
+ FdinfoEntry *fe;
int sk;
pr_info("Opening standalone socket (id %#x ino %#x peer %#x)\n",
@@ -1197,7 +1203,7 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
close(sks[1]);
sk = sks[0];
- } else if (ui->ue->type == SOCK_DGRAM && !ui->queuer) {
+ } else if (ui->ue->type == SOCK_DGRAM && !ui->queuer && !ui->nr_senders) {
struct sockaddr_un addr;
int sks[2];
@@ -1276,12 +1282,79 @@ static int open_unixsk_standalone(struct unix_sk_info *ui)
if (restore_socket_opts(sk, ui->ue->opts))
return -1;
+ if (ui->nr_senders) {
+ fle = xzalloc(sizeof(*fle));
+ fe = xzalloc(sizeof(*fe));
+ fle->fe = fe;
+
+ ui->transport_fd = find_unused_fd(&rsti(current)->used, -1);
+ fe->fd = ui->transport_fd;
+ pr_info("Found unused fd=%d for transport\n", ui->transport_fd);
+ collect_used_fd(fle, rsti(current));
+
+ if (ui->transport_fd == sk) {
+ sk = dup(sk);
+ if (sk < 0) {
+ pr_err("Can't dup\n");
+ return -1;
+ }
+ }
+
+ fle = file_master(&ui->d);
+ ui->transport_fd = dup2(fle->fe->fd, ui->transport_fd);
+ if (ui->transport_fd < 0) {
+ pr_err("Can't dup\n");
+ return -1;
+ }
+ close(fle->fe->fd);
+ }
+
return sk;
}
+static int send_sk_to_receivers(int sk, struct unix_sk_info *ui)
+{
+ struct sk_ino *si, *tmp;
+ int tsk, ret = 0;
+
+ tsk = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (tsk < 0) {
+ pr_perror("Can't make transport socket");
+ return -1;
+ }
+
+ list_for_each_entry_safe(si, tmp, &ui->receivers, list) {
+ struct unix_sk_info *receiver;
+ struct fdinfo_list_entry *fle;
+
+ pr_info("Sending fd=%d to ino=%d\n", sk, si->ino);
+
+ receiver = find_unix_sk_by_ino(si->ino);
+ if (!receiver) {
+ pr_err("Can't find receiver: ino=%u", si->ino);
+ ret = -1;
+ break;
+ }
+
+ fle = file_master(&receiver->d);
+
+ if (send_fd_to_peer(sk, fle, tsk)) {
+ pr_err("Can't send sk to receiver\n");
+ ret = -1;
+ break;
+ }
+ list_del(&si->list);
+ }
+
+ close(tsk);
+
+ return ret;
+}
+
static int open_unix_sk(struct file_desc *d)
{
struct unix_sk_info *ui;
+ int sk, err = 0;
ui = container_of(d, struct unix_sk_info, d);
@@ -1289,13 +1362,60 @@ static int open_unix_sk(struct file_desc *d)
if (inherited_fd(d, &unixsk_fd)) {
ui->ue->uflags |= USK_INHERIT;
- return unixsk_fd;
+ sk = unixsk_fd;
} else if (ui->flags & USK_PAIR_MASTER)
- return open_unixsk_pair_master(ui);
+ sk = open_unixsk_pair_master(ui);
else if (ui->flags & USK_PAIR_SLAVE)
- return open_unixsk_pair_slave(ui);
+ sk = open_unixsk_pair_slave(ui);
else
- return open_unixsk_standalone(ui);
+ sk = open_unixsk_standalone(ui);
+
+ if (sk >= 0 && !list_empty(&ui->receivers))
+ err = send_sk_to_receivers(sk, ui);
+ if (err < 0) {
+ close(sk);
+ sk = -1;
+ }
+
+ return sk;
+}
+
+static int receive_unix_sk(struct file_desc *d, int fd)
+{
+ struct fdinfo_list_entry *fle;
+ struct unix_sk_info *ui;
+ int i, sk, ret = 0;
+
+ ui = container_of(d, struct unix_sk_info, d);
+ if (!ui->nr_senders)
+ return 0;
+
+ BUG_ON(ui->ue->type != SOCK_DGRAM);
+ BUG_ON(!list_empty(&ui->receivers));
+
+ ui->foreign_fds = xmalloc(ui->nr_senders * sizeof(int));
+ if (!ui->foreign_fds)
+ return -1;
+
+ for (i = 0; i < ui->nr_senders; i++) {
+ sk = recv_fd(ui->transport_fd);
+ if (sk < 0) {
+ pr_err("Can't recv fd\n");
+ ret = -1;
+ break;
+ }
+
+ pr_info("Received foreign fd=%d\n", sk);
+ ui->foreign_fds[i] = sk;
+ }
+
+ fle = find_used_fd(&rsti(current)->used, ui->transport_fd);
+ list_del(&fle->used_list);
+ xfree(fle->fe);
+ xfree(fle);
+ close(ui->transport_fd);
+
+ return ret;
}
static char *socket_d_name(struct file_desc *d, char *buf, size_t s)
@@ -1316,6 +1436,7 @@ static char *socket_d_name(struct file_desc *d, char *buf, size_t s)
static struct file_desc_ops unix_desc_ops = {
.type = FD_TYPES__UNIXSK,
.open = open_unix_sk,
+ .receive = receive_unix_sk,
.post_open = post_open_unix_sk,
.want_transport = unixsk_should_open_transport,
.name = socket_d_name,
More information about the CRIU
mailing list