BUG/MEDIUM: splice/threads: pipe reuse list was not protected.

The list is now protected using a global spinlock.
This commit is contained in:
Emeric Brun 2017-11-07 11:19:48 +01:00 committed by Willy Tarreau
parent 926fa4c098
commit d8b3b65faa
2 changed files with 30 additions and 12 deletions

View File

@ -174,6 +174,7 @@ enum lock_label {
DNS_LOCK, DNS_LOCK,
PID_LIST_LOCK, PID_LIST_LOCK,
EMAIL_ALERTS_LOCK, EMAIL_ALERTS_LOCK,
PIPES_LOCK,
LOCK_LABELS LOCK_LABELS
}; };
struct lock_stat { struct lock_stat {
@ -262,7 +263,8 @@ static inline void show_lock_stats()
"UPDATED_SERVERS", "LBPRM", "SIGNALS", "STK_TABLE", "STK_SESS", "UPDATED_SERVERS", "LBPRM", "SIGNALS", "STK_TABLE", "STK_SESS",
"APPLETS", "PEER", "BUF_WQ", "STREAMS", "SSL", "SSL_GEN_CERTS", "APPLETS", "PEER", "BUF_WQ", "STREAMS", "SSL", "SSL_GEN_CERTS",
"PATREF", "PATEXP", "PATLRU", "VARS", "COMP_POOL", "LUA", "PATREF", "PATEXP", "PATLRU", "VARS", "COMP_POOL", "LUA",
"NOTIF", "SPOE_APPLET", "DNS", "PID_LIST", "EMAIL_ALERTS" }; "NOTIF", "SPOE_APPLET", "DNS", "PID_LIST", "EMAIL_ALERTS",
"PIPES" };
int lbl; int lbl;
for (lbl = 0; lbl < LOCK_LABELS; lbl++) { for (lbl = 0; lbl < LOCK_LABELS; lbl++) {

View File

@ -21,6 +21,7 @@
struct pool_head *pool2_pipe = NULL; struct pool_head *pool2_pipe = NULL;
struct pipe *pipes_live = NULL; /* pipes which are still ready to use */ struct pipe *pipes_live = NULL; /* pipes which are still ready to use */
HA_SPINLOCK_T pipes_lock; /* lock used to protect pipes list */
int pipes_used = 0; /* # of pipes in use (2 fds each) */ int pipes_used = 0; /* # of pipes in use (2 fds each) */
int pipes_free = 0; /* # of pipes unused */ int pipes_free = 0; /* # of pipes unused */
@ -30,6 +31,7 @@ static void init_pipe()
pool2_pipe = create_pool("pipe", sizeof(struct pipe), MEM_F_SHARED); pool2_pipe = create_pool("pipe", sizeof(struct pipe), MEM_F_SHARED);
pipes_used = 0; pipes_used = 0;
pipes_free = 0; pipes_free = 0;
HA_SPIN_INIT(&pipes_lock);
} }
/* return a pre-allocated empty pipe. Try to allocate one if there isn't any /* return a pre-allocated empty pipe. Try to allocate one if there isn't any
@ -37,27 +39,28 @@ static void init_pipe()
*/ */
struct pipe *get_pipe() struct pipe *get_pipe()
{ {
struct pipe *ret; struct pipe *ret = NULL;
int pipefd[2]; int pipefd[2];
HA_SPIN_LOCK(PIPES_LOCK, &pipes_lock);
if (likely(pipes_live)) { if (likely(pipes_live)) {
ret = pipes_live; ret = pipes_live;
pipes_live = pipes_live->next; pipes_live = pipes_live->next;
pipes_free--; pipes_free--;
pipes_used++; pipes_used++;
return ret; goto out;
} }
if (pipes_used >= global.maxpipes) if (pipes_used >= global.maxpipes)
return NULL; goto out;
ret = pool_alloc2(pool2_pipe); ret = pool_alloc2(pool2_pipe);
if (!ret) if (!ret)
return NULL; goto out;
if (pipe(pipefd) < 0) { if (pipe(pipefd) < 0) {
pool_free2(pool2_pipe, ret); pool_free2(pool2_pipe, ret);
return NULL; goto out;
} }
#ifdef F_SETPIPE_SZ #ifdef F_SETPIPE_SZ
if (global.tune.pipesize) if (global.tune.pipesize)
@ -68,18 +71,28 @@ struct pipe *get_pipe()
ret->cons = pipefd[0]; ret->cons = pipefd[0];
ret->next = NULL; ret->next = NULL;
pipes_used++; pipes_used++;
out:
HA_SPIN_UNLOCK(PIPES_LOCK, &pipes_lock);
return ret; return ret;
} }
static void inline __kill_pipe(struct pipe *p)
{
close(p->prod);
close(p->cons);
pool_free2(pool2_pipe, p);
pipes_used--;
return;
}
/* destroy a pipe, possibly because an error was encountered on it. Its FDs /* destroy a pipe, possibly because an error was encountered on it. Its FDs
* will be closed and it will not be reinjected into the live pool. * will be closed and it will not be reinjected into the live pool.
*/ */
void kill_pipe(struct pipe *p) void kill_pipe(struct pipe *p)
{ {
close(p->prod); HA_SPIN_LOCK(PIPES_LOCK, &pipes_lock);
close(p->cons); __kill_pipe(p);
pool_free2(pool2_pipe, p); HA_SPIN_UNLOCK(PIPES_LOCK, &pipes_lock);
pipes_used--;
return; return;
} }
@ -89,14 +102,17 @@ void kill_pipe(struct pipe *p)
*/ */
void put_pipe(struct pipe *p) void put_pipe(struct pipe *p)
{ {
HA_SPIN_LOCK(PIPES_LOCK, &pipes_lock);
if (p->data) { if (p->data) {
kill_pipe(p); __kill_pipe(p);
return; goto out;
} }
p->next = pipes_live; p->next = pipes_live;
pipes_live = p; pipes_live = p;
pipes_free++; pipes_free++;
pipes_used--; pipes_used--;
out:
HA_SPIN_UNLOCK(PIPES_LOCK, &pipes_lock);
} }