Причины, по которым процедура rps использует spinlock с local_irq_disable
Сейчас я изучаю код внутренней сети ядра, особенно код RPS. Вы знаете, есть много функций об этом. Но я сосредоточен на некоторых функциях обработки очереди SMP, таких как enqueue_to_backlog
а также process_backlog
,
Интересно о синхронизации между двумя ядрами (или одноядерными) с помощью двух функций - enqueue_to_backlog
а также process_backlog
-.
В этих функциях ядро (A) содержит spin_lock
другого ядра (B) для очереди пакетов в input_pkt_queue
и планирование напи ядра (B). И ядро (B) также содержит spin_lock
для сращивания input_pkt_queue
в process_queue
ядра (B) и удаление напи график самостоятельно. я знаю это spin_lock
следует удерживать, чтобы два ядра не могли обращаться к одной и той же очереди друг другу во время обработки очереди.
Но я не могу понять, почему spin_lock
называется с local_irq_disable
(или же local_irq_save
). Я думаю, что нет доступа к очередям или rps_lock
ядра (B) посредством контекста прерываний (TH), когда прерывания (TH) выгружают текущий контекст (softirq, BH). - Конечно, доступ к napi-структуре для планирования napi может быть получен через TH, но она удерживает отключение irq до тех пор, пока пакет не будет поставлен в очередь. Поэтому мне интересно, почему spin_lock
вызывается с отключением irq.
Я думаю, что невозможно исключить текущий контекст (napi, softirq) с помощью другой BH, такой как тасклет. Это правда? И я хочу знать, отключает ли local_irq_disable все ядра irq или буквально только irq текущего ядра? На самом деле, я прочитал книгу о разработке ядра, но мне кажется, что я недостаточно разбираюсь в вытеснении.
Объяснил бы причины, по которым процедура rps используется spin_lock
с local_irq_disable
?
1 ответ
Отключение прерываний влияет на текущее ядро (только). Следовательно, если этот параметр отключен, никакой другой код на том же ядре не сможет помешать обновлению структуры данных. Смысл спин-блокировки состоит в том, чтобы распространить "блокировку" на другие ядра (хотя это совместное, а не аппаратное обеспечение).
Опасно / безответственно брать спин-блокировку в ядре, не отключая прерывания, потому что, когда затем происходит прерывание, текущий код будет приостановлен, и теперь вы препятствуете прогрессу других ядер, пока работает какой-то несвязанный обработчик прерываний (даже если другой пользовательский процесс или тасклет в исходном ядре не сможет выгрузить). Другие ядра могут быть в контексте прерывания или BH, и теперь вы задерживаете всю систему. Предполагается, что спин-блокировки будут удерживаться в течение очень коротких периодов времени для критических обновлений общих структур данных.
Это также хороший способ генерировать тупики. Подумайте, реплицировался ли описанный выше сценарий в другую подсистему (или, возможно, другое устройство в той же подсистеме, но я опишу первое)
Здесь ядро A получает спин-блокировку в подсистеме 1 без отключения прерываний. В то же время ядро B получает спин-блокировку в подсистеме 2 также без отключения прерываний. Теперь, что произойдет, если прерывание, связанное с подсистемой 2, произойдет на ядре A, и при выполнении обработчика прерываний подсистемы 2 ядру A необходимо обновить структуру, защищенную спин-блокировкой, хранящейся в ядре B. Но примерно в то же время подсистема 1 прерывание происходит в ядре B, которому необходимо обновить структуру данных в этой подсистеме. Теперь оба ядра заняты ожиданием спин-блокировки, удерживаемой другим ядром, и вся система зависает до тех пор, пока вы не выполните полный сброс.