From dc340a900d9d2e7258888ade8192796c36a8a389 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 28 Jun 2009 23:10:19 +0200 Subject: [PATCH] [MEDIUM] splice: set the capability on each stream_interface The splice code did not consider compatibility between both ends of the connection. Now we set different capabilities on each stream interface, depending on what the protocol can splice to/from. Right now, only TCP is supported. Thanks to this, we're now able to automatically detect when splice() is not implemented and automatically disable it on one end instead of reporting errors to the upper layer. --- include/types/stream_interface.h | 5 ++++- src/backend.c | 1 + src/client.c | 2 +- src/session.c | 4 ++++ src/stream_sock.c | 10 ++++++++++ 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/types/stream_interface.h b/include/types/stream_interface.h index bb4a9e3b5..f97aa624d 100644 --- a/include/types/stream_interface.h +++ b/include/types/stream_interface.h @@ -67,14 +67,17 @@ enum { SI_FL_ERR = 0x0002, /* a non-recoverable error has occurred */ SI_FL_WAIT_ROOM = 0x0004, /* waiting for space to store incoming data */ SI_FL_WAIT_DATA = 0x0008, /* waiting for more data to send */ + SI_FL_CAP_SPLTCP = 0x0010, /* splicing possible from/to TCP */ }; +#define SI_FL_CAP_SPLICE (SI_FL_CAP_SPLTCP) + struct stream_interface { unsigned int state; /* SI_ST* */ unsigned int prev_state;/* SI_ST*, copy of previous state */ void *owner; /* generally a (struct task*) */ int fd; /* file descriptor for a stream driver when known */ - unsigned int flags; /* SI_FL_*, must be cleared before I/O */ + unsigned int flags; unsigned int exp; /* wake up time for connect, queue, turn-around, ... */ void (*shutr)(struct stream_interface *); /* shutr function */ void (*shutw)(struct stream_interface *); /* shutw function */ diff --git a/src/backend.c b/src/backend.c index 5cea8089b..bf9f78922 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1985,6 +1985,7 @@ int connect_server(struct session *s) EV_FD_SET(fd, DIR_WR); /* for connect status */ s->req->cons->state = SI_ST_CON; + s->req->cons->flags |= SI_FL_CAP_SPLTCP; /* TCP supports splicing */ if (s->srv) { s->flags |= SN_CURR_SESS; s->srv->cur_sess++; diff --git a/src/client.c b/src/client.c index 45c576dd6..3e2099eed 100644 --- a/src/client.c +++ b/src/client.c @@ -190,7 +190,7 @@ int event_accept(int fd) { s->si[0].chk_rcv = stream_sock_chk_rcv; s->si[0].chk_snd = stream_sock_chk_snd; s->si[0].fd = cfd; - s->si[0].flags = SI_FL_NONE; + s->si[0].flags = SI_FL_NONE | SI_FL_CAP_SPLTCP; /* TCP splicing capable */ s->si[0].exp = TICK_ETERNITY; s->si[1].state = s->si[1].prev_state = SI_ST_INI; diff --git a/src/session.c b/src/session.c index 9ea45e1ba..d3f3710c9 100644 --- a/src/session.c +++ b/src/session.c @@ -184,6 +184,7 @@ int sess_update_st_con_tcp(struct session *s, struct stream_interface *si) if (unlikely(si->flags & (SI_FL_EXP|SI_FL_ERR))) { si->exp = TICK_ETERNITY; si->state = SI_ST_CER; + si->flags &= ~SI_FL_CAP_SPLICE; fd_delete(si->fd); if (si->err_type) @@ -207,6 +208,7 @@ int sess_update_st_con_tcp(struct session *s, struct stream_interface *si) si->shutw(si); si->err_type |= SI_ET_CONN_ABRT; si->err_loc = s->srv; + si->flags &= ~SI_FL_CAP_SPLICE; if (s->srv_error) s->srv_error(s, si); return 1; @@ -859,6 +861,7 @@ resync_stream_interface: if (!(s->req->flags & (BF_KERN_SPLICING|BF_SHUTR)) && s->req->to_forward && (global.tune.options & GTUNE_USE_SPLICE) && + (s->si[0].flags & s->si[1].flags & SI_FL_CAP_SPLICE) && (pipes_used < global.maxpipes) && (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_REQ) || (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) && @@ -966,6 +969,7 @@ resync_stream_interface: if (!(s->rep->flags & (BF_KERN_SPLICING|BF_SHUTR)) && s->rep->to_forward && (global.tune.options & GTUNE_USE_SPLICE) && + (s->si[0].flags & s->si[1].flags & SI_FL_CAP_SPLICE) && (pipes_used < global.maxpipes) && (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_RTR) || (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) && diff --git a/src/stream_sock.c b/src/stream_sock.c index 52305c5e3..438ff0a5e 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -186,6 +186,16 @@ static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si) retval = -1; break; } + + if (errno == ENOSYS) { + /* splice not supported on this end, disable it */ + b->flags &= ~BF_KERN_SPLICING; + si->flags &= ~SI_FL_CAP_SPLICE; + put_pipe(b->pipe); + b->pipe = NULL; + return -1; + } + /* here we have another error */ si->flags |= SI_FL_ERR; retval = 1;