mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Forbid locking altogether when RCU reader is active
This commit is contained in:
parent
1e77e6e1b2
commit
6eea722d3f
@ -44,9 +44,8 @@ extern _Thread_local struct domain_generic **last_locked;
|
|||||||
#define DOMAIN(type) struct domain__##type
|
#define DOMAIN(type) struct domain__##type
|
||||||
#define DOMAIN_ORDER(type) OFFSETOF(struct lock_order, type)
|
#define DOMAIN_ORDER(type) OFFSETOF(struct lock_order, type)
|
||||||
|
|
||||||
#define DOMAIN_NEW(type) (DOMAIN(type)) { .type = domain_new(DOMAIN_ORDER(type), 1) }
|
#define DOMAIN_NEW(type) (DOMAIN(type)) { .type = domain_new(DOMAIN_ORDER(type)) }
|
||||||
#define DOMAIN_NEW_RCU_SYNC(type) (DOMAIN(type)) { .type = domain_new(DOMAIN_ORDER(type), 0) }
|
struct domain_generic *domain_new(uint order);
|
||||||
struct domain_generic *domain_new(uint order, bool allow_rcu);
|
|
||||||
|
|
||||||
#define DOMAIN_FREE(type, d) domain_free((d).type)
|
#define DOMAIN_FREE(type, d) domain_free((d).type)
|
||||||
void domain_free(struct domain_generic *);
|
void domain_free(struct domain_generic *);
|
||||||
|
@ -56,7 +56,7 @@ net_lock_revive_unlock(netindex_hash *h, struct netindex *i)
|
|||||||
netindex_hash *
|
netindex_hash *
|
||||||
netindex_hash_new(pool *sp, event_list *cleanup_target, u8 type)
|
netindex_hash_new(pool *sp, event_list *cleanup_target, u8 type)
|
||||||
{
|
{
|
||||||
DOMAIN(attrs) dom = DOMAIN_NEW_RCU_SYNC(attrs);
|
DOMAIN(attrs) dom = DOMAIN_NEW(attrs);
|
||||||
LOCK_DOMAIN(attrs, dom);
|
LOCK_DOMAIN(attrs, dom);
|
||||||
|
|
||||||
pool *p = rp_new(sp, dom.attrs, "Network index");
|
pool *p = rp_new(sp, dom.attrs, "Network index");
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
_Atomic u64 rcu_global_phase = RCU_GP_PHASE;
|
_Atomic u64 rcu_global_phase = RCU_GP_PHASE;
|
||||||
_Thread_local struct rcu_thread this_rcu_thread;
|
_Thread_local struct rcu_thread this_rcu_thread;
|
||||||
_Thread_local uint rcu_blocked;
|
|
||||||
|
|
||||||
static struct rcu_thread * _Atomic rcu_thread_list = NULL;
|
static struct rcu_thread * _Atomic rcu_thread_list = NULL;
|
||||||
|
|
||||||
@ -36,9 +35,6 @@ rcu_critical(struct rcu_thread *t, u64 phase)
|
|||||||
void
|
void
|
||||||
synchronize_rcu(void)
|
synchronize_rcu(void)
|
||||||
{
|
{
|
||||||
if (!rcu_blocked && (last_locked > &locking_stack.meta))
|
|
||||||
bug("Forbidden to synchronize RCU unless an appropriate lock is taken");
|
|
||||||
|
|
||||||
/* Increment phase */
|
/* Increment phase */
|
||||||
u64 phase = atomic_fetch_add_explicit(&rcu_global_phase, RCU_GP_PHASE, memory_order_acq_rel);
|
u64 phase = atomic_fetch_add_explicit(&rcu_global_phase, RCU_GP_PHASE, memory_order_acq_rel);
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ struct rcu_thread {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern _Thread_local struct rcu_thread this_rcu_thread;
|
extern _Thread_local struct rcu_thread this_rcu_thread;
|
||||||
extern _Thread_local uint rcu_blocked;
|
|
||||||
|
|
||||||
static inline void rcu_read_lock(void)
|
static inline void rcu_read_lock(void)
|
||||||
{
|
{
|
||||||
|
@ -1843,7 +1843,7 @@ ea_show_list(struct cli *c, ea_list *eal)
|
|||||||
void
|
void
|
||||||
rta_init(void)
|
rta_init(void)
|
||||||
{
|
{
|
||||||
attrs_domain = DOMAIN_NEW_RCU_SYNC(attrs);
|
attrs_domain = DOMAIN_NEW(attrs);
|
||||||
|
|
||||||
RTA_LOCK;
|
RTA_LOCK;
|
||||||
rta_pool = rp_new(&root_pool, attrs_domain.attrs, "Attributes");
|
rta_pool = rp_new(&root_pool, attrs_domain.attrs, "Attributes");
|
||||||
|
@ -3090,7 +3090,7 @@ rt_setup(pool *pp, struct rtable_config *cf)
|
|||||||
pool *sp = birdloop_pool(loop);
|
pool *sp = birdloop_pool(loop);
|
||||||
|
|
||||||
/* Create the table domain and pool */
|
/* Create the table domain and pool */
|
||||||
DOMAIN(rtable) dom = DOMAIN_NEW_RCU_SYNC(rtable);
|
DOMAIN(rtable) dom = DOMAIN_NEW(rtable);
|
||||||
LOCK_DOMAIN(rtable, dom);
|
LOCK_DOMAIN(rtable, dom);
|
||||||
|
|
||||||
pool *p = rp_newf(sp, dom.rtable, "Routing table data %s", cf->name);
|
pool *p = rp_newf(sp, dom.rtable, "Routing table data %s", cf->name);
|
||||||
@ -3256,7 +3256,7 @@ rt_init(void)
|
|||||||
init_list(&routing_tables);
|
init_list(&routing_tables);
|
||||||
init_list(&deleted_routing_tables);
|
init_list(&deleted_routing_tables);
|
||||||
ev_init_list(&rt_cork.queue, &main_birdloop, "Route cork release");
|
ev_init_list(&rt_cork.queue, &main_birdloop, "Route cork release");
|
||||||
rt_cork.dom = DOMAIN_NEW_RCU_SYNC(resource);
|
rt_cork.dom = DOMAIN_NEW(resource);
|
||||||
idm_init(&rtable_idm, rt_table_pool, 256);
|
idm_init(&rtable_idm, rt_table_pool, 256);
|
||||||
|
|
||||||
ea_register_init(&ea_roa_aggregated);
|
ea_register_init(&ea_roa_aggregated);
|
||||||
|
@ -1948,7 +1948,7 @@ bgp_init_pending_tx(struct bgp_channel *c)
|
|||||||
ASSERT_DIE(c->c.out_table == NULL);
|
ASSERT_DIE(c->c.out_table == NULL);
|
||||||
ASSERT_DIE(c->tx == NULL);
|
ASSERT_DIE(c->tx == NULL);
|
||||||
|
|
||||||
DOMAIN(rtable) dom = DOMAIN_NEW_RCU_SYNC(rtable);
|
DOMAIN(rtable) dom = DOMAIN_NEW(rtable);
|
||||||
LOCK_DOMAIN(rtable, dom);
|
LOCK_DOMAIN(rtable, dom);
|
||||||
pool *p = rp_newf(c->pool, dom.rtable, "%s.%s TX", c->c.proto->name, c->c.name);
|
pool *p = rp_newf(c->pool, dom.rtable, "%s.%s TX", c->c.proto->name, c->c.name);
|
||||||
|
|
||||||
|
@ -215,6 +215,14 @@ alloc_page(void)
|
|||||||
/* Reinstate the stack with zero */
|
/* Reinstate the stack with zero */
|
||||||
PAGE_STACK_PUT(NULL);
|
PAGE_STACK_PUT(NULL);
|
||||||
|
|
||||||
|
if (rcu_read_active())
|
||||||
|
{
|
||||||
|
/* We can't lock and we actually shouldn't alloc either when rcu is active
|
||||||
|
* but that's a quest for another day. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
/* If there is any free page kept cold, we use that. */
|
/* If there is any free page kept cold, we use that. */
|
||||||
LOCK_DOMAIN(resource, empty_pages_domain);
|
LOCK_DOMAIN(resource, empty_pages_domain);
|
||||||
if (empty_pages) {
|
if (empty_pages) {
|
||||||
@ -244,6 +252,8 @@ alloc_page(void)
|
|||||||
if (fp)
|
if (fp)
|
||||||
return fp;
|
return fp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* And in the worst case, allocate some new pages by mmap() */
|
/* And in the worst case, allocate some new pages by mmap() */
|
||||||
void *ptr = alloc_sys_page();
|
void *ptr = alloc_sys_page();
|
||||||
ajlog(ptr, NULL, 0, AJT_ALLOC_MMAP);
|
ajlog(ptr, NULL, 0, AJT_ALLOC_MMAP);
|
||||||
|
@ -50,29 +50,27 @@ _Thread_local struct domain_generic **last_locked = NULL;
|
|||||||
struct domain_generic {
|
struct domain_generic {
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
uint order;
|
uint order;
|
||||||
bool forbidden_when_reading_rcu;
|
|
||||||
struct domain_generic **prev;
|
struct domain_generic **prev;
|
||||||
struct lock_order *locked_by;
|
struct lock_order *locked_by;
|
||||||
const char *name;
|
const char *name;
|
||||||
pool *pool;
|
pool *pool;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DOMAIN_INIT(_order, _allow_rcu) { \
|
#define DOMAIN_INIT(_order) { \
|
||||||
.mutex = PTHREAD_MUTEX_INITIALIZER, \
|
.mutex = PTHREAD_MUTEX_INITIALIZER, \
|
||||||
.order = _order, \
|
.order = _order, \
|
||||||
.forbidden_when_reading_rcu = !_allow_rcu, \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct domain_generic the_bird_domain_gen = DOMAIN_INIT(OFFSETOF(struct lock_order, the_bird), 1);
|
static struct domain_generic the_bird_domain_gen = DOMAIN_INIT(OFFSETOF(struct lock_order, the_bird));
|
||||||
|
|
||||||
DOMAIN(the_bird) the_bird_domain = { .the_bird = &the_bird_domain_gen };
|
DOMAIN(the_bird) the_bird_domain = { .the_bird = &the_bird_domain_gen };
|
||||||
|
|
||||||
struct domain_generic *
|
struct domain_generic *
|
||||||
domain_new(uint order, bool allow_rcu)
|
domain_new(uint order)
|
||||||
{
|
{
|
||||||
ASSERT_DIE(order < sizeof(struct lock_order));
|
ASSERT_DIE(order < sizeof(struct lock_order));
|
||||||
struct domain_generic *dg = xmalloc(sizeof(struct domain_generic));
|
struct domain_generic *dg = xmalloc(sizeof(struct domain_generic));
|
||||||
*dg = (struct domain_generic) DOMAIN_INIT(order, allow_rcu);
|
*dg = (struct domain_generic) DOMAIN_INIT(order);
|
||||||
return dg;
|
return dg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,11 +106,8 @@ void do_lock(struct domain_generic *dg, struct domain_generic **lsp)
|
|||||||
memcpy(&stack_copy, &locking_stack, sizeof(stack_copy));
|
memcpy(&stack_copy, &locking_stack, sizeof(stack_copy));
|
||||||
struct domain_generic **lll = last_locked;
|
struct domain_generic **lll = last_locked;
|
||||||
|
|
||||||
if (dg->forbidden_when_reading_rcu)
|
|
||||||
if (rcu_read_active())
|
if (rcu_read_active())
|
||||||
bug("Locking of this lock forbidden while RCU reader is active");
|
bug("Locking forbidden while RCU reader is active");
|
||||||
else
|
|
||||||
rcu_blocked++;
|
|
||||||
|
|
||||||
if ((char *) lsp - (char *) &locking_stack != dg->order)
|
if ((char *) lsp - (char *) &locking_stack != dg->order)
|
||||||
bug("Trying to lock on bad position: order=%u, lsp=%p, base=%p", dg->order, lsp, &locking_stack);
|
bug("Trying to lock on bad position: order=%u, lsp=%p, base=%p", dg->order, lsp, &locking_stack);
|
||||||
@ -139,9 +134,6 @@ void do_lock(struct domain_generic *dg, struct domain_generic **lsp)
|
|||||||
|
|
||||||
void do_unlock(struct domain_generic *dg, struct domain_generic **lsp)
|
void do_unlock(struct domain_generic *dg, struct domain_generic **lsp)
|
||||||
{
|
{
|
||||||
if (dg->forbidden_when_reading_rcu)
|
|
||||||
ASSERT_DIE(rcu_blocked--);
|
|
||||||
|
|
||||||
if ((char *) lsp - (char *) &locking_stack != dg->order)
|
if ((char *) lsp - (char *) &locking_stack != dg->order)
|
||||||
bug("Trying to unlock on bad position: order=%u, lsp=%p, base=%p", dg->order, lsp, &locking_stack);
|
bug("Trying to unlock on bad position: order=%u, lsp=%p, base=%p", dg->order, lsp, &locking_stack);
|
||||||
|
|
||||||
|
@ -1581,7 +1581,7 @@ birdloop_run_timer(timer *tm)
|
|||||||
static struct birdloop *
|
static struct birdloop *
|
||||||
birdloop_vnew_internal(pool *pp, uint order, struct birdloop_pickup_group *group, const char *name, va_list args)
|
birdloop_vnew_internal(pool *pp, uint order, struct birdloop_pickup_group *group, const char *name, va_list args)
|
||||||
{
|
{
|
||||||
struct domain_generic *dg = domain_new(order, 1);
|
struct domain_generic *dg = domain_new(order);
|
||||||
DG_LOCK(dg);
|
DG_LOCK(dg);
|
||||||
|
|
||||||
pool *p = rp_vnewf(pp, dg, name, args);
|
pool *p = rp_vnewf(pp, dg, name, args);
|
||||||
|
Loading…
Reference in New Issue
Block a user