diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c index f7eef5218..bfc5cb932 100644 --- a/criu/sk-tcp.c +++ b/criu/sk-tcp.c @@ -257,12 +257,7 @@ static int read_tcp_queue(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, if (read_img_buf(img, buf, len) < 0) goto err; - if (queue == TCP_SEND_QUEUE) - data->outq_data = buf; - else - data->inq_data = buf; - - return 0; + return libsoccr_set_queue_bytes(sk, queue, buf, SOCCR_MEM_EXCL); err: xfree(buf); @@ -379,8 +374,6 @@ static int restore_tcp_conn_state(int sk, struct libsoccr_sk *socr, struct inet_ return 0; err_c: - xfree(data.inq_data); - xfree(data.outq_data); tcp_stream_entry__free_unpacked(tse, NULL); close_image(img); err: diff --git a/soccr/soccr.c b/soccr/soccr.c index d0c8668c4..d44a2e541 100644 --- a/soccr/soccr.c +++ b/soccr/soccr.c @@ -104,10 +104,14 @@ static int tcp_repair_off(int fd) struct libsoccr_sk { int fd; + unsigned flags; char *recv_queue; char *send_queue; }; +#define SK_FLAG_FREE_RQ 0x1 +#define SK_FLAG_FREE_SQ 0x2 + struct libsoccr_sk *libsoccr_pause(int fd) { struct libsoccr_sk *ret; @@ -121,6 +125,7 @@ struct libsoccr_sk *libsoccr_pause(int fd) return NULL; } + ret->flags = 0; ret->recv_queue = NULL; ret->send_queue = NULL; ret->fd = fd; @@ -130,8 +135,10 @@ struct libsoccr_sk *libsoccr_pause(int fd) void libsoccr_resume(struct libsoccr_sk *sk) { tcp_repair_off(sk->fd); - free(sk->send_queue); - free(sk->recv_queue); + if (sk->flags & SK_FLAG_FREE_RQ) + free(sk->recv_queue); + if (sk->flags & SK_FLAG_FREE_SQ) + free(sk->send_queue); free(sk); } @@ -345,6 +352,8 @@ int libsoccr_save(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigne if (get_window(sk, data)) return -4; + sk->flags |= SK_FLAG_FREE_SQ | SK_FLAG_FREE_RQ; + if (get_queue(sk->fd, TCP_RECV_QUEUE, &data->inq_seq, data->inq_len, &sk->recv_queue)) return -4; @@ -623,7 +632,7 @@ static int restore_fin_in_snd_queue(int sk, int acked) return ret; } -static int libsoccr_set_queue_bytes(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size, +static int libsoccr_restore_queue(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size, int queue, char *buf); int libsoccr_restore(struct libsoccr_sk *sk, @@ -634,10 +643,10 @@ int libsoccr_restore(struct libsoccr_sk *sk, if (libsoccr_set_sk_data_noq(sk, data, data_size)) return -1; - if (libsoccr_set_queue_bytes(sk, data, sizeof(*data), TCP_RECV_QUEUE, data->inq_data)) + if (libsoccr_restore_queue(sk, data, sizeof(*data), TCP_RECV_QUEUE, sk->recv_queue)) return -1; - if (libsoccr_set_queue_bytes(sk, data, sizeof(*data), TCP_SEND_QUEUE, data->outq_data)) + if (libsoccr_restore_queue(sk, data, sizeof(*data), TCP_SEND_QUEUE, sk->send_queue)) return -1; if (data->flags & SOCCR_FLAGS_WINDOW) { @@ -749,9 +758,12 @@ static int send_queue(struct libsoccr_sk *sk, int queue, char *buf, __u32 len) return __send_queue(sk, queue, buf, len); } -static int libsoccr_set_queue_bytes(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size, +static int libsoccr_restore_queue(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size, int queue, char *buf) { + if (!buf) + return 0; + if (!data || data_size < SOCR_DATA_MIN_SIZE) return -1; @@ -793,3 +805,25 @@ static int libsoccr_set_queue_bytes(struct libsoccr_sk *sk, struct libsoccr_sk_d return -5; } + +#define SET_Q_FLAGS (SOCCR_MEM_EXCL) +int libsoccr_set_queue_bytes(struct libsoccr_sk *sk, int queue_id, char *bytes, unsigned flags) +{ + if (flags & ~SET_Q_FLAGS) + return -1; + + switch (queue_id) { + case TCP_RECV_QUEUE: + sk->recv_queue = bytes; + if (flags & SOCCR_MEM_EXCL) + sk->flags |= SK_FLAG_FREE_RQ; + return 0; + case TCP_SEND_QUEUE: + sk->send_queue = bytes; + if (flags & SOCCR_MEM_EXCL) + sk->flags |= SK_FLAG_FREE_SQ; + return 0; + } + + return -1; +} diff --git a/soccr/soccr.h b/soccr/soccr.h index 1e4bfb357..cd7327154 100644 --- a/soccr/soccr.h +++ b/soccr/soccr.h @@ -91,9 +91,6 @@ struct libsoccr_sk_data { __u32 rcv_wnd; __u32 rcv_wup; - char *inq_data; - char *outq_data; - union libsoccr_addr src_addr; union libsoccr_addr dst_addr; }; @@ -196,6 +193,8 @@ char *libsoccr_get_queue_bytes(struct libsoccr_sk *sk, int queue_id, unsigned fl * sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); * * h = libsoccr_pause(sk) + * libsoccr_set_queue_bytes(h, TCP_SEND_QUEUE, outq); + * libsoccr_set_queue_bytes(h, TCP_RECV_QUEUE, inq); * libsoccr_restore(h, &data, sizeof(data)) * * libsoccr_resume(h) @@ -204,6 +203,13 @@ char *libsoccr_get_queue_bytes(struct libsoccr_sk *sk, int queue_id, unsigned fl * enabled back. */ +/* + * Set a pointer on the send/recv queue data. + * If flags have SOCCR_MEM_EXCL, the buffer is stolen by the library and is + * free()-ed after libsoccr_resume(). + */ +int libsoccr_set_queue_bytes(struct libsoccr_sk *sk, int queue_id, char *bytes, unsigned flags); + /* * Performs restore actions on bind()-ed socket */