Безопасно ли использовать rcu_dereference() внутри local_bh_disable()/local_bh_enable()?

local_bh_disable-функция меняется для каждого процессора (в случае с x86 и последними ядрами) __preempt_count или же current_thread_info()->preempt_count иначе.

В любом случае, это дает нам льготный период, поэтому мы можем предположить, что это будет излишним rcu_read_lock() внутри local_bh_disable(), Действительно: в более ранних ядрах мы можем видеть, что local_bh_disable() используется для RCU и rcu_dereference() впоследствии вызывается внутри, например, dev_queue_xmit-функции. Потом local_bh_disable() был заменен на rcu_read_lock_bh()что в итоге стало немного сложнее, чем просто звонить local_bh_disable(), Теперь это выглядит так:

static inline void rcu_read_lock_bh(void)
{
   local_bh_disable();
   __acquire(RCU_BH);
   rcu_lock_acquire(&rcu_bh_lock_map);
   RCU_LOCKDEP_WARN(!rcu_is_watching(),"rcu_read_lock_bh() used illegally while idle");
}

Также есть достаточно статей, описывающих API RCU. Здесь мы можем видеть:

Нужно ли обрабатывать обработчики NMI, обработчики hardirq и сегменты кода с отключенным вытеснением (будь то с помощью preempt_disable (), local_irq_save (), local_bh_disable () или каким-либо другим механизмом), как если бы они были явными считывателями RCU? Если это так, RCU-sched является единственным выбором, который будет работать для вас.

Это говорит нам об использовании RCU Sched API в таких случаях, поэтому rcu_dereference_sched() должно помочь Из этой всеобъемлющей таблицы мы можем понять, что rcu_dereference() следует использовать только внутри rcu_read_lock/rcu_read_unlock-markers.

Однако это недостаточно ясно. Могу ли я использовать (в случае современных ядер) rcu_dereference() внутри local_bh_disable/local_bh_enable-маркеры без опасений что-нибудь пойдут не так?

PS В моем случае я не могу изменить код вызова local_bh_disable например, позвонить rcu_read_lock_bh, так что мой код запускается с bh уже отключен. Также используется обычный RCU API. Таким образом, это чревато rcu_read_lock вложенный в local_bh_disable,

1 ответ

Решение

Вы не должны смешивать и сочетать API. Если вам нужно использовать API RCU-bh, вам нужно использовать rcu_dereference_bh,

Вы можете видеть, что если вы позвонилиrcu_dereference_checkпослеrcu_read_lock_bhбыло бы правильно предположить, что он не вызывается в критическом разделе на стороне чтения RCU; противопоставить призыв lock_is_held(&rcu_lock_map) с rcu_lock_acquire(&rcu_bh_lock_map); в вашем фрагменте выше.

Документация по ядру для RCU здесь (поиск в разделе "rcu_dereference()") дает явный пример правильного использования; rcu_dereference* может быть правильно вызван только после соответствующего rcu_read_lock* Функция завершена.

Другие вопросы по тегам