mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 14:25:49 +00:00
inet: Rework inet sk dumping on new fdinfo scheme
Now every inetsk fd dump results in a new entry in the fdinfo.img file. Sockets itself are dumped into inetsk.img global image file. On restore the generic fdinfo redistribution algo is used and inet sockets are opened only when required. Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
@@ -62,6 +62,7 @@ static char *fdtype2s(u8 type)
|
|||||||
[FDINFO_MAP] = "map",
|
[FDINFO_MAP] = "map",
|
||||||
[FDINFO_CWD] = "cwd",
|
[FDINFO_CWD] = "cwd",
|
||||||
[FDINFO_EXE] = "exe",
|
[FDINFO_EXE] = "exe",
|
||||||
|
[FDINFO_INETSK] = "isk",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (type > FDINFO_UND && type < FD_INFO_MAX)
|
if (type > FDINFO_UND && type < FD_INFO_MAX)
|
||||||
|
14
files.c
14
files.c
@@ -19,6 +19,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "util-net.h"
|
#include "util-net.h"
|
||||||
#include "lock.h"
|
#include "lock.h"
|
||||||
|
#include "sockets.h"
|
||||||
|
|
||||||
static struct fdinfo_desc *fdinfo_descs;
|
static struct fdinfo_desc *fdinfo_descs;
|
||||||
static int nr_fdinfo_descs;
|
static int nr_fdinfo_descs;
|
||||||
@@ -313,7 +314,15 @@ static int open_fd(int pid, struct fdinfo_entry *fe,
|
|||||||
if ((fi->pid != pid) || (fe->addr != fi->addr))
|
if ((fi->pid != pid) || (fe->addr != fi->addr))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
tmp = open_fe_fd(fe);
|
switch (fe->type) {
|
||||||
|
case FDINFO_REG:
|
||||||
|
tmp = open_fe_fd(fe);
|
||||||
|
break;
|
||||||
|
case FDINFO_INETSK:
|
||||||
|
tmp = open_inet_sk(fe);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (tmp < 0)
|
if (tmp < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -429,8 +438,7 @@ static int open_fdinfo(int pid, struct fdinfo_entry *fe, int *fdinfo_fd, int sta
|
|||||||
pr_info("\t%d: Got fd for %lx users %d\n", pid,
|
pr_info("\t%d: Got fd for %lx users %d\n", pid,
|
||||||
fe->addr, futex_get(&fi->users));
|
fe->addr, futex_get(&fi->users));
|
||||||
|
|
||||||
BUG_ON(fe->type != FDINFO_REG);
|
BUG_ON(fd_is_special(fe));
|
||||||
|
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case FD_STATE_PREP:
|
case FD_STATE_PREP:
|
||||||
|
@@ -27,7 +27,6 @@ enum {
|
|||||||
CR_FD_PIPES,
|
CR_FD_PIPES,
|
||||||
CR_FD_SIGACT,
|
CR_FD_SIGACT,
|
||||||
CR_FD_UNIXSK,
|
CR_FD_UNIXSK,
|
||||||
CR_FD_INETSK,
|
|
||||||
CR_FD_ITIMERS,
|
CR_FD_ITIMERS,
|
||||||
CR_FD_CREDS,
|
CR_FD_CREDS,
|
||||||
_CR_FD_TASK_TO,
|
_CR_FD_TASK_TO,
|
||||||
@@ -50,6 +49,7 @@ enum {
|
|||||||
_CR_FD_GLOB_FROM,
|
_CR_FD_GLOB_FROM,
|
||||||
CR_FD_SK_QUEUES,
|
CR_FD_SK_QUEUES,
|
||||||
CR_FD_REG_FILES,
|
CR_FD_REG_FILES,
|
||||||
|
CR_FD_INETSK,
|
||||||
_CR_FD_GLOB_TO,
|
_CR_FD_GLOB_TO,
|
||||||
|
|
||||||
CR_FD_MAX
|
CR_FD_MAX
|
||||||
@@ -102,7 +102,7 @@ extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX];
|
|||||||
#define FMT_FNAME_PSTREE "pstree.img"
|
#define FMT_FNAME_PSTREE "pstree.img"
|
||||||
#define FMT_FNAME_SIGACTS "sigacts-%d.img"
|
#define FMT_FNAME_SIGACTS "sigacts-%d.img"
|
||||||
#define FMT_FNAME_UNIXSK "unixsk-%d.img"
|
#define FMT_FNAME_UNIXSK "unixsk-%d.img"
|
||||||
#define FMT_FNAME_INETSK "inetsk-%d.img"
|
#define FMT_FNAME_INETSK "inetsk.img"
|
||||||
#define FMT_FNAME_ITIMERS "itimers-%d.img"
|
#define FMT_FNAME_ITIMERS "itimers-%d.img"
|
||||||
#define FMT_FNAME_CREDS "creds-%d.img"
|
#define FMT_FNAME_CREDS "creds-%d.img"
|
||||||
#define FMT_FNAME_UTSNS "utsns-%d.img"
|
#define FMT_FNAME_UTSNS "utsns-%d.img"
|
||||||
|
@@ -34,7 +34,7 @@ enum fd_types {
|
|||||||
FDINFO_UND,
|
FDINFO_UND,
|
||||||
FDINFO_REG,
|
FDINFO_REG,
|
||||||
FDINFO_MAP,
|
FDINFO_MAP,
|
||||||
|
FDINFO_INETSK,
|
||||||
FDINFO_CWD,
|
FDINFO_CWD,
|
||||||
FDINFO_EXE,
|
FDINFO_EXE,
|
||||||
|
|
||||||
@@ -93,7 +93,6 @@ struct unix_sk_entry {
|
|||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct inet_sk_entry {
|
struct inet_sk_entry {
|
||||||
u32 fd;
|
|
||||||
u32 id;
|
u32 id;
|
||||||
u8 family;
|
u8 family;
|
||||||
u8 type;
|
u8 type;
|
||||||
|
@@ -27,6 +27,8 @@ extern int try_dump_socket(pid_t pid, int fd, const struct cr_fdset *cr_fdset,
|
|||||||
|
|
||||||
extern int collect_sockets(void);
|
extern int collect_sockets(void);
|
||||||
extern int prepare_sockets(int pid);
|
extern int prepare_sockets(int pid);
|
||||||
|
struct fdinfo_entry;
|
||||||
|
extern int open_inet_sk(struct fdinfo_entry *fe);
|
||||||
struct cr_options;
|
struct cr_options;
|
||||||
extern void show_unixsk(int fd, struct cr_options *);
|
extern void show_unixsk(int fd, struct cr_options *);
|
||||||
extern void show_inetsk(int fd, struct cr_options *);
|
extern void show_inetsk(int fd, struct cr_options *);
|
||||||
|
134
sockets.c
134
sockets.c
@@ -41,6 +41,7 @@ struct socket_desc {
|
|||||||
unsigned int family;
|
unsigned int family;
|
||||||
unsigned int ino;
|
unsigned int ino;
|
||||||
struct socket_desc *next;
|
struct socket_desc *next;
|
||||||
|
int already_dumped;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct unix_sk_desc {
|
struct unix_sk_desc {
|
||||||
@@ -177,9 +178,9 @@ static void show_one_inet_img(const char *act, const struct inet_sk_entry *e)
|
|||||||
pr_perror("Failed to translate address");
|
pr_perror("Failed to translate address");
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("\t%s: fd %d family %d type %d proto %d port %d "
|
pr_debug("\t%s: family %d type %d proto %d port %d "
|
||||||
"state %d src_addr %s\n",
|
"state %d src_addr %s\n",
|
||||||
act, e->fd, e->family, e->type, e->proto, e->src_port,
|
act, e->family, e->type, e->proto, e->src_port,
|
||||||
e->state, src_addr);
|
e->state, src_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,19 +238,29 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dump_one_inet(const struct socket_desc *_sk, int fd,
|
static int dump_one_inet(struct socket_desc *_sk, int fd,
|
||||||
const struct cr_fdset *cr_fdset,
|
const struct cr_fdset *cr_fdset,
|
||||||
struct sk_queue *queue)
|
struct sk_queue *queue)
|
||||||
{
|
{
|
||||||
const struct inet_sk_desc *sk = (struct inet_sk_desc *)_sk;
|
struct inet_sk_desc *sk = (struct inet_sk_desc *)_sk;
|
||||||
struct inet_sk_entry ie;
|
struct inet_sk_entry ie;
|
||||||
|
struct fdinfo_entry fe;
|
||||||
|
|
||||||
if (!can_dump_inet_sk(sk))
|
if (!can_dump_inet_sk(sk))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
fe.addr = fd;
|
||||||
|
fe.type = FDINFO_INETSK;
|
||||||
|
fe.id = sk->sd.ino;
|
||||||
|
|
||||||
|
if (write_img(fdset_fd(cr_fdset, CR_FD_FDINFO), &fe))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (sk->sd.already_dumped)
|
||||||
|
return 0;
|
||||||
|
|
||||||
memset(&ie, 0, sizeof(ie));
|
memset(&ie, 0, sizeof(ie));
|
||||||
|
|
||||||
ie.fd = fd;
|
|
||||||
ie.id = sk->sd.ino;
|
ie.id = sk->sd.ino;
|
||||||
ie.family = sk->sd.family;
|
ie.family = sk->sd.family;
|
||||||
ie.type = sk->type;
|
ie.type = sk->type;
|
||||||
@@ -261,12 +272,13 @@ static int dump_one_inet(const struct socket_desc *_sk, int fd,
|
|||||||
memcpy(ie.src_addr, sk->src_addr, sizeof(u32) * 4);
|
memcpy(ie.src_addr, sk->src_addr, sizeof(u32) * 4);
|
||||||
memcpy(ie.dst_addr, sk->dst_addr, sizeof(u32) * 4);
|
memcpy(ie.dst_addr, sk->dst_addr, sizeof(u32) * 4);
|
||||||
|
|
||||||
if (write_img(fdset_fd(cr_fdset, CR_FD_INETSK), &ie))
|
if (write_img(fdset_fd(glob_fdset, CR_FD_INETSK), &ie))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
pr_info("Dumping inet socket at %d\n", fd);
|
pr_info("Dumping inet socket at %d\n", fd);
|
||||||
show_one_inet("Dumping", sk);
|
show_one_inet("Dumping", sk);
|
||||||
show_one_inet_img("Dumped", &ie);
|
show_one_inet_img("Dumped", &ie);
|
||||||
|
sk->sd.already_dumped = 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -372,7 +384,7 @@ err:
|
|||||||
int try_dump_socket(pid_t pid, int fd, const struct cr_fdset *cr_fdset,
|
int try_dump_socket(pid_t pid, int fd, const struct cr_fdset *cr_fdset,
|
||||||
struct sk_queue *queue)
|
struct sk_queue *queue)
|
||||||
{
|
{
|
||||||
const struct socket_desc *sk;
|
struct socket_desc *sk;
|
||||||
struct statfs fst;
|
struct statfs fst;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char path[64];
|
char path[64];
|
||||||
@@ -1176,24 +1188,56 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_inet_sk(const struct inet_sk_entry *ie, int *img_fd)
|
static int read_inetsk_image(u32 id, struct inet_sk_entry *ie)
|
||||||
|
{
|
||||||
|
int ifd;
|
||||||
|
|
||||||
|
ifd = open_image_ro(CR_FD_INETSK);
|
||||||
|
if (ifd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = read_img_eof(ifd, ie);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
pr_err("Can't find inet sk %u\n", id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ie->id == id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(ifd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_inet_sk(struct fdinfo_entry *fe)
|
||||||
{
|
{
|
||||||
int sk;
|
int sk;
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
|
struct inet_sk_entry ie;
|
||||||
|
|
||||||
show_one_inet_img("Restore", ie);
|
if (read_inetsk_image(fe->id, &ie))
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (ie->family != AF_INET) {
|
show_one_inet_img("Restore", &ie);
|
||||||
pr_err("Unsupported socket family: %d\n", ie->family);
|
|
||||||
|
if (ie.family != AF_INET) {
|
||||||
|
pr_err("Unsupported socket family: %d\n", ie.family);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ie->type != SOCK_STREAM) && (ie->type != SOCK_DGRAM)) {
|
if ((ie.type != SOCK_STREAM) && (ie.type != SOCK_DGRAM)) {
|
||||||
pr_err("Unsupported socket type: %d\n", ie->type);
|
pr_err("Unsupported socket type: %d\n", ie.type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sk = socket(ie->family, ie->type, ie->proto);
|
sk = socket(ie.family, ie.type, ie.proto);
|
||||||
if (sk < 0) {
|
if (sk < 0) {
|
||||||
pr_perror("Can't create unix socket");
|
pr_perror("Can't create unix socket");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1204,37 +1248,37 @@ static int open_inet_sk(const struct inet_sk_entry *ie, int *img_fd)
|
|||||||
* bind() and listen(), and that's all.
|
* bind() and listen(), and that's all.
|
||||||
*/
|
*/
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sin_family = ie->family;
|
addr.sin_family = ie.family;
|
||||||
addr.sin_port = htons(ie->src_port);
|
addr.sin_port = htons(ie.src_port);
|
||||||
memcpy(&addr.sin_addr.s_addr, ie->src_addr, sizeof(unsigned int) * 4);
|
memcpy(&addr.sin_addr.s_addr, ie.src_addr, sizeof(unsigned int) * 4);
|
||||||
|
|
||||||
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
||||||
pr_perror("Can't bind to a socket");
|
pr_perror("Can't bind to a socket");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ie->state == TCP_LISTEN) {
|
if (ie.state == TCP_LISTEN) {
|
||||||
if (ie->proto != IPPROTO_TCP) {
|
if (ie.proto != IPPROTO_TCP) {
|
||||||
pr_err("Wrong socket in listen state %d\n", ie->proto);
|
pr_err("Wrong socket in listen state %d\n", ie.proto);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(sk, ie->backlog) == -1) {
|
if (listen(sk, ie.backlog) == -1) {
|
||||||
pr_perror("Can't listen on a socket");
|
pr_perror("Can't listen on a socket");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ie->state == TCP_ESTABLISHED) {
|
if (ie.state == TCP_ESTABLISHED) {
|
||||||
if (ie->proto != IPPROTO_UDP) {
|
if (ie.proto != IPPROTO_UDP) {
|
||||||
pr_err("Connected TCP socket in image\n");
|
pr_err("Connected TCP socket in image\n");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sin_family = ie->family;
|
addr.sin_family = ie.family;
|
||||||
addr.sin_port = htons(ie->dst_port);
|
addr.sin_port = htons(ie.dst_port);
|
||||||
memcpy(&addr.sin_addr.s_addr, ie->dst_addr, sizeof(ie->dst_addr));
|
memcpy(&addr.sin_addr.s_addr, ie.dst_addr, sizeof(ie.dst_addr));
|
||||||
|
|
||||||
if (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
if (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||||
pr_perror("Can't connect UDP socket back");
|
pr_perror("Can't connect UDP socket back");
|
||||||
@@ -1242,49 +1286,19 @@ static int open_inet_sk(const struct inet_sk_entry *ie, int *img_fd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (move_img_fd(img_fd, ie->fd))
|
return sk;
|
||||||
return -1;
|
|
||||||
|
|
||||||
return reopen_fd_as(ie->fd, sk);
|
|
||||||
|
|
||||||
err:
|
err:
|
||||||
close(sk);
|
close(sk);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prepare_inet_sockets(int pid)
|
|
||||||
{
|
|
||||||
int isk_fd, ret = -1;
|
|
||||||
|
|
||||||
isk_fd = open_image_ro(CR_FD_INETSK, pid);
|
|
||||||
if (isk_fd < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
struct inet_sk_entry ie;
|
|
||||||
|
|
||||||
ret = read_img_eof(isk_fd, &ie);
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ret = open_inet_sk(&ie, &isk_fd);
|
|
||||||
if (ret)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
err:
|
|
||||||
close(isk_fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int prepare_sockets(int pid)
|
int prepare_sockets(int pid)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
pr_info("%d: Opening sockets\n", pid);
|
pr_info("%d: Opening sockets\n", pid);
|
||||||
err = prepare_unix_sockets(pid);
|
return prepare_unix_sockets(pid);
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
return prepare_inet_sockets(pid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_inetsk(int fd, struct cr_options *o)
|
void show_inetsk(int fd, struct cr_options *o)
|
||||||
@@ -1314,8 +1328,8 @@ void show_inetsk(int fd, struct cr_options *o)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_msg("fd %d family %d type %d proto %d state %d %s:%d <-> %s:%d\n",
|
pr_msg("id %x family %d type %d proto %d state %d %s:%d <-> %s:%d\n",
|
||||||
ie.fd, ie.family, ie.type, ie.proto, ie.state,
|
ie.id, ie.family, ie.type, ie.proto, ie.state,
|
||||||
src_addr, ie.src_port, dst_addr, ie.dst_port);
|
src_addr, ie.src_port, dst_addr, ie.dst_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user