]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] splice: set the capability on each stream_interface
authorWilly Tarreau <w@1wt.eu>
Sun, 28 Jun 2009 21:10:19 +0000 (23:10 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 28 Jun 2009 21:10:19 +0000 (23:10 +0200)
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
src/backend.c
src/client.c
src/session.c
src/stream_sock.c

index bb4a9e3b5f2f20867d0a1edd0f8053af55bc267c..f97aa624da0928320b4119b0cbb1dc7331933f50 100644 (file)
@@ -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 */
index 5cea8089bdd33ca987f2325a8daf591145f732c7..bf9f78922f85d00c5ca0076ce11c4ddee409c810 100644 (file)
@@ -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++;
index 45c576dd60e64d9d6ec868ebb24dccf68322fbb4..3e2099eedd7e9b0812ae77b1b0ae5af2009dbc2e 100644 (file)
@@ -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;
index 9ea45e1ba905b46350cd7ce9cd360aac2314bf8f..d3f3710c90aeac8183a849996ba4e82c814966b3 100644 (file)
@@ -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) &&
index 52305c5e34ee7d4513cfb2a991d1e3f7bd272161..438ff0a5e82a9ca6ce5a1e22b8f80504af5356e6 100644 (file)
@@ -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;