Commit 84710812 authored by Pavel Emelyanov's avatar Pavel Emelyanov

unix: Add support for shutdown sockets

Get the info from kernel diag message (it should always be there)
and restore the shutdown at the very end.
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 223dce83
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define CR_SOCKETS_H__ #define CR_SOCKETS_H__
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -59,5 +60,20 @@ extern int do_dump_opt(int sk, int level, int name, void *val, int len); ...@@ -59,5 +60,20 @@ extern int do_dump_opt(int sk, int level, int name, void *val, int len);
extern int do_restore_opt(int sk, int level, int name, void *val, int len); extern int do_restore_opt(int sk, int level, int name, void *val, int len);
#define restore_opt(s, l, n, f) do_restore_opt(s, l, n, f, sizeof(*f)) #define restore_opt(s, l, n, f) do_restore_opt(s, l, n, f, sizeof(*f))
#define sk_encode_shutdown(img, mask) do { \
/* \
* protobuf SK_SHUTDOWN__ bits match those \
* reported by kernel \
*/ \
(img)->shutdown = mask; \
if ((img)->shutdown != SK_SHUTDOWN__NONE) \
(img)->has_shutdown = true; \
} while (0)
static inline int sk_decode_shutdown(int val)
{
static const int hows[] = {-1, SHUT_RD, SHUT_WR, SHUT_RDWR};
return hows[val];
}
#endif /* CR_SOCKETS_H__ */ #endif /* CR_SOCKETS_H__ */
...@@ -49,6 +49,7 @@ enum { ...@@ -49,6 +49,7 @@ enum {
UNIX_DIAG_ICONS, UNIX_DIAG_ICONS,
UNIX_DIAG_RQLEN, UNIX_DIAG_RQLEN,
UNIX_DIAG_MEMINFO, UNIX_DIAG_MEMINFO,
UNIX_DIAG_SHUTDOWN,
UNIX_DIAG_MAX, UNIX_DIAG_MAX,
}; };
......
...@@ -18,3 +18,10 @@ message sk_opts_entry { ...@@ -18,3 +18,10 @@ message sk_opts_entry {
optional uint32 so_bound_dev = 15; optional uint32 so_bound_dev = 15;
} }
enum sk_shutdown {
NONE = 0;
READ = 1;
WRITE = 2;
BOTH = 3;
}
...@@ -29,4 +29,6 @@ message unix_sk_entry { ...@@ -29,4 +29,6 @@ message unix_sk_entry {
* so we need to carry it as byte sequence... * so we need to carry it as byte sequence...
*/ */
required bytes name = 11; required bytes name = 11;
optional sk_shutdown shutdown = 12;
} }
...@@ -36,6 +36,7 @@ struct unix_sk_desc { ...@@ -36,6 +36,7 @@ struct unix_sk_desc {
char *name; char *name;
unsigned int nr_icons; unsigned int nr_icons;
unsigned int *icons; unsigned int *icons;
unsigned char shutdown;
struct list_head list; struct list_head list;
}; };
...@@ -138,6 +139,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) ...@@ -138,6 +139,8 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
ue.opts = &skopts; ue.opts = &skopts;
ue.uflags = 0; ue.uflags = 0;
sk_encode_shutdown(&ue, sk->shutdown);
if (ue.peer) { if (ue.peer) {
struct unix_sk_desc *peer; struct unix_sk_desc *peer;
...@@ -168,6 +171,22 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p) ...@@ -168,6 +171,22 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
list_add_tail(&peer->list, &unix_sockets); list_add_tail(&peer->list, &unix_sockets);
} }
} }
if ((ue.type != SOCK_DGRAM) && (
((ue.shutdown == SK_SHUTDOWN__READ) &&
(peer->shutdown != SK_SHUTDOWN__WRITE)) ||
((ue.shutdown == SK_SHUTDOWN__WRITE) &&
(peer->shutdown != SK_SHUTDOWN__READ)) ||
((ue.shutdown == SK_SHUTDOWN__BOTH) &&
(peer->shutdown != SK_SHUTDOWN__BOTH)) )) {
/*
* On restore we assume, that stream pairs must
* be shut down from one end only
*/
pr_err("Shutdown mismatch %u:%d -> %u:%d\n",
ue.ino, ue.shutdown, peer->sd.ino, peer->shutdown);
goto err;
}
} else if (ue.state == TCP_ESTABLISHED) { } else if (ue.state == TCP_ESTABLISHED) {
const struct unix_sk_listen_icon *e; const struct unix_sk_listen_icon *e;
...@@ -248,6 +267,13 @@ static int unix_collect_one(const struct unix_diag_msg *m, ...@@ -248,6 +267,13 @@ static int unix_collect_one(const struct unix_diag_msg *m,
d->state = m->udiag_state; d->state = m->udiag_state;
INIT_LIST_HEAD(&d->list); INIT_LIST_HEAD(&d->list);
if (!tb[UNIX_DIAG_SHUTDOWN]) {
pr_err("No socket shutdown info\n");
goto err;
}
d->shutdown = *(u8 *)RTA_DATA(tb[UNIX_DIAG_SHUTDOWN]);
if (tb[UNIX_DIAG_PEER]) if (tb[UNIX_DIAG_PEER])
d->peer_ino = *(int *)RTA_DATA(tb[UNIX_DIAG_PEER]); d->peer_ino = *(int *)RTA_DATA(tb[UNIX_DIAG_PEER]);
...@@ -456,6 +482,24 @@ void show_unixsk(int fd, struct cr_options *o) ...@@ -456,6 +482,24 @@ void show_unixsk(int fd, struct cr_options *o)
pb_show_plain_pretty(fd, PB_UNIXSK, "1:%#x 2:%#x 3:%d 4:%d 5:%d 6:%d 7:%d 8:%#x 11:S"); pb_show_plain_pretty(fd, PB_UNIXSK, "1:%#x 2:%#x 3:%d 4:%d 5:%d 6:%d 7:%d 8:%#x 11:S");
} }
static int shutdown_unix_sk(int sk, struct unix_sk_info *ui)
{
int how;
UnixSkEntry *ue = ui->ue;
if (!ue->has_shutdown || ue->shutdown == SK_SHUTDOWN__NONE)
return 0;
how = sk_decode_shutdown(ue->shutdown);
if (shutdown(sk, how)) {
pr_perror("Can't shutdown unix socket");
return -1;
}
pr_debug("Socket %#x is shut down %d\n", ue->ino, how);
return 0;
}
static int post_open_unix_sk(struct file_desc *d, int fd) static int post_open_unix_sk(struct file_desc *d, int fd)
{ {
struct unix_sk_info *ui; struct unix_sk_info *ui;
...@@ -500,6 +544,9 @@ static int post_open_unix_sk(struct file_desc *d, int fd) ...@@ -500,6 +544,9 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
if (restore_socket_opts(fle->fe->fd, ui->ue->opts)) if (restore_socket_opts(fle->fe->fd, ui->ue->opts))
return -1; return -1;
if (shutdown_unix_sk(fle->fe->fd, ui))
return -1;
return 0; return 0;
} }
...@@ -566,6 +613,9 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui) ...@@ -566,6 +613,9 @@ static int open_unixsk_pair_master(struct unix_sk_info *ui)
if (rst_file_params(sk[0], ui->ue->fown, ui->ue->flags)) if (rst_file_params(sk[0], ui->ue->fown, ui->ue->flags))
return -1; return -1;
if (shutdown_unix_sk(sk[0], ui))
return -1;
tsk = socket(PF_UNIX, SOCK_DGRAM, 0); tsk = socket(PF_UNIX, SOCK_DGRAM, 0);
if (tsk < 0) { if (tsk < 0) {
pr_perror("Can't make transport socket"); pr_perror("Can't make transport socket");
...@@ -610,6 +660,14 @@ static int open_unixsk_pair_slave(struct unix_sk_info *ui) ...@@ -610,6 +660,14 @@ static int open_unixsk_pair_slave(struct unix_sk_info *ui)
if (restore_socket_opts(sk, ui->ue->opts)) if (restore_socket_opts(sk, ui->ue->opts))
return -1; return -1;
if (ui->ue->type == SOCK_DGRAM)
/*
* Stream socket's "slave" end will be shut down
* together with master
*/
if (shutdown_unix_sk(sk, ui))
return -1;
return sk; return sk;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment