0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 12:18:42 +00:00

Forbid locking altogether when RCU reader is active

This commit is contained in:
Maria Matejka 2024-06-27 08:42:11 +02:00
parent 1e77e6e1b2
commit 6eea722d3f
10 changed files with 24 additions and 28 deletions

View File

@ -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 *);

View File

@ -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");

View File

@ -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);

View File

@ -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)
{ {

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 forbidden while RCU reader is active");
bug("Locking of this lock 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);

View File

@ -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);