BUG/MEDIUM: listener: duplicate inherited FDs if needed
Since commit 36d9097cf ("MINOR: fd: Add BUG_ON checks on fd_insert()"), there is currently a test in fd_insert() to detect that we're not trying to reinsert an FD that had already been inserted. This test catches the following anomalies: frontend fail1 bind fd@0 bind fd@0 and: frontend fail2 bind fd@0 shards 2 What happens is that clone_listener() is called on a listener already having an FD, and when sock_{inet,unix}_bind_receiver() are called, the same FD will be registered multiple times and rightfully crash in the sanity check. It wouldn't be correct to block shards though (e.g. they could be used in a default-bind line). What looks like a safer and more future-proof approach simply is to dup() the FD so that each listener has one copy. This is also the only solution that might allow later to support more than 64 threads on an inherited FD. This needs to be backported as far as 2.4. Better wait for at least one extra -dev version before backporting though, as the bug should not be triggered often anyway.
This commit is contained in:
parent
b714e11aaa
commit
145b17fd2f
@ -312,6 +312,24 @@ int sock_inet_bind_receiver(struct receiver *rx, char **errmsg)
|
||||
}
|
||||
}
|
||||
|
||||
if (ext && fd < global.maxsock && fdtab[fd].owner) {
|
||||
/* This FD was already bound so this means that it was already
|
||||
* known and registered before parsing, hence it's an inherited
|
||||
* FD. The only reason why it's already known here is that it
|
||||
* has been registered multiple times (multiple listeners on the
|
||||
* same, or a "shards" directive on the line). There cannot be
|
||||
* multiple listeners on one FD but at least we can create a
|
||||
* new one from the original one. We won't reconfigure it,
|
||||
* however, as this was already done for the first one.
|
||||
*/
|
||||
fd = dup(fd);
|
||||
if (fd == -1) {
|
||||
err |= ERR_RETRYABLE | ERR_ALERT;
|
||||
memprintf(errmsg, "cannot dup() receiving socket (%s)", strerror(errno));
|
||||
goto bind_return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd >= global.maxsock) {
|
||||
err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
|
||||
memprintf(errmsg, "not enough free sockets (raise '-n' parameter)");
|
||||
|
@ -226,6 +226,24 @@ int sock_unix_bind_receiver(struct receiver *rx, char **errmsg)
|
||||
}
|
||||
|
||||
fd_ready:
|
||||
if (ext && fd < global.maxsock && fdtab[fd].owner) {
|
||||
/* This FD was already bound so this means that it was already
|
||||
* known and registered before parsing, hence it's an inherited
|
||||
* FD. The only reason why it's already known here is that it
|
||||
* has been registered multiple times (multiple listeners on the
|
||||
* same, or a "shards" directive on the line). There cannot be
|
||||
* multiple listeners on one FD but at least we can create a
|
||||
* new one from the original one. We won't reconfigure it,
|
||||
* however, as this was already done for the first one.
|
||||
*/
|
||||
fd = dup(fd);
|
||||
if (fd == -1) {
|
||||
err |= ERR_RETRYABLE | ERR_ALERT;
|
||||
memprintf(errmsg, "cannot dup() receiving socket (%s)", strerror(errno));
|
||||
goto bind_return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd >= global.maxsock) {
|
||||
err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
|
||||
memprintf(errmsg, "not enough free sockets (raise '-n' parameter)");
|
||||
|
Loading…
x
Reference in New Issue
Block a user