Delay rehashing until we're not processing events
Fixes crash introduced by 0ab6dbbc65
. It's
probably a regression since it defeats a system designed to stop this
from happening, but I didn't dig through the history.
rehash() closes listeners. If we happen to get a single epoll() result
that wants to first rehash and then accept a connection, the epoll info
will point to a freed rb_fde_t. Other selectors should have similar
problems, but we didn't investigate that.
rb_fde_ts are normally batched up and freed outside the event
processing, but as of the above commit close_listeners() screws that up
by closing pending FDs immediately in order to create new listeners.
I think it might be a bit better to revert this behaviour and simply not
close listeners if we are going to open new ones over them, but have
opted for the smallest reasonable change I can think of.
Helped-by: Eric Mertens <emertens@gmail.com>
This commit is contained in:
parent
460e793274
commit
59ea3c6753
4 changed files with 53 additions and 9 deletions
|
@ -642,16 +642,18 @@ attach_conf(struct Client *client_p, struct ConfItem *aconf)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
struct rehash_data {
|
||||||
* rehash
|
bool sig;
|
||||||
*
|
};
|
||||||
* Actual REHASH service routine. Called with sig == 0 if it has been called
|
|
||||||
* as a result of an operator issuing this command, else assume it has been
|
static void
|
||||||
* called as a result of the server receiving a HUP signal.
|
service_rehash(void *data_)
|
||||||
*/
|
|
||||||
bool
|
|
||||||
rehash(bool sig)
|
|
||||||
{
|
{
|
||||||
|
struct rehash_data *data = data_;
|
||||||
|
bool sig = data->sig;
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
rb_dlink_node *n;
|
rb_dlink_node *n;
|
||||||
|
|
||||||
hook_data_rehash hdata = { sig };
|
hook_data_rehash hdata = { sig };
|
||||||
|
@ -684,6 +686,21 @@ rehash(bool sig)
|
||||||
privilegeset_cleanup_rehash();
|
privilegeset_cleanup_rehash();
|
||||||
|
|
||||||
call_hook(h_rehash, &hdata);
|
call_hook(h_rehash, &hdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rehash
|
||||||
|
*
|
||||||
|
* Called with sig == 0 if it has been called as a result of an operator
|
||||||
|
* issuing this command, else assume it has been called as a result of the
|
||||||
|
* server receiving a HUP signal.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
rehash(bool sig)
|
||||||
|
{
|
||||||
|
struct rehash_data *data = rb_malloc(sizeof *data);
|
||||||
|
data->sig = sig;
|
||||||
|
rb_defer(service_rehash, data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,7 @@ int rb_ignore_errno(int);
|
||||||
void rb_setselect(rb_fde_t *, unsigned int type, PF * handler, void *client_data);
|
void rb_setselect(rb_fde_t *, unsigned int type, PF * handler, void *client_data);
|
||||||
void rb_init_netio(void);
|
void rb_init_netio(void);
|
||||||
int rb_select(unsigned long);
|
int rb_select(unsigned long);
|
||||||
|
void rb_defer(void (*)(void *), void *);
|
||||||
int rb_fd_ssl(rb_fde_t *F);
|
int rb_fd_ssl(rb_fde_t *F);
|
||||||
int rb_get_fd(rb_fde_t *F);
|
int rb_get_fd(rb_fde_t *F);
|
||||||
const char *rb_get_ssl_strerror(rb_fde_t *F);
|
const char *rb_get_ssl_strerror(rb_fde_t *F);
|
||||||
|
|
|
@ -51,6 +51,14 @@ static rb_bh *fd_heap;
|
||||||
static rb_dlink_list timeout_list;
|
static rb_dlink_list timeout_list;
|
||||||
static rb_dlink_list closed_list;
|
static rb_dlink_list closed_list;
|
||||||
|
|
||||||
|
struct defer
|
||||||
|
{
|
||||||
|
rb_dlink_node node;
|
||||||
|
void (*fn)(void *);
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
static rb_dlink_list defer_list;
|
||||||
|
|
||||||
static struct ev_entry *rb_timeout_ev;
|
static struct ev_entry *rb_timeout_ev;
|
||||||
|
|
||||||
|
|
||||||
|
@ -2015,10 +2023,27 @@ rb_setselect(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
|
||||||
setselect_handler(F, type, handler, client_data);
|
setselect_handler(F, type, handler, client_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_defer(void (*fn)(void *), void *data)
|
||||||
|
{
|
||||||
|
struct defer *defer = rb_malloc(sizeof *defer);
|
||||||
|
defer->fn = fn;
|
||||||
|
defer->data = data;
|
||||||
|
rb_dlinkAdd(defer, &defer->node, &defer_list);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_select(unsigned long timeout)
|
rb_select(unsigned long timeout)
|
||||||
{
|
{
|
||||||
int ret = select_handler(timeout);
|
int ret = select_handler(timeout);
|
||||||
|
rb_dlink_node *ptr, *next;
|
||||||
|
RB_DLINK_FOREACH_SAFE(ptr, next, defer_list.head)
|
||||||
|
{
|
||||||
|
struct defer *defer = ptr->data;
|
||||||
|
defer->fn(defer->data);
|
||||||
|
rb_dlinkDelete(ptr, &defer_list);
|
||||||
|
rb_free(defer);
|
||||||
|
}
|
||||||
rb_close_pending_fds();
|
rb_close_pending_fds();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ rb_ctime
|
||||||
rb_current_time
|
rb_current_time
|
||||||
rb_current_time_tv
|
rb_current_time_tv
|
||||||
rb_date
|
rb_date
|
||||||
|
rb_defer
|
||||||
rb_destroy_patricia
|
rb_destroy_patricia
|
||||||
rb_dictionary_add
|
rb_dictionary_add
|
||||||
rb_dictionary_create
|
rb_dictionary_create
|
||||||
|
|
Loading…
Reference in a new issue