#linux #linux-kernel #network-programming #linux-device-driver #dma
#linux #linux-ядро #сетевое программирование #linux-драйвер устройства #dma
Вопрос:
Редактировать:
Не уверен, проблема это или нет, но вот что я заметил:
rx_skbuffers выделяются в двух местах: один раз, когда драйвер инициализирован, он вызывает __netdev_alloc_skb_ip_align с GPF_KERNEL, и второй раз, если rx_skbuff уже установлен.освобожденный он вызывает netdev_alloc_skb_ip_align (который внутренне использует GPF_ATOMIC).
Разве эти выделения skb не должны вызываться с помощью GPF_DMA ?
==========================================================================
У меня возникли проблемы с повреждением данных в драйвере Ethernet (для ST MAC 10/100/1000) Я работаю с. Драйвер работает на Allwinner A20 (ARM Cortex-A7).
Некоторые подробности:
- Драйвер содержит кольцо Rx sk_buffers (выделенных с
__netdev_alloc_skb_ip_align
помощью ). - Данные (
rx_skbuff[i]->data
) каждого из sk_buffers сопоставляются с использованием DMAdma_map_single
. - Сопоставление выполнено успешно (проверено с
dma_mapping_error
помощью).
Проблема:
Через некоторое время (минуты, часы, дни… очень случайно), ядро паникует из-за повреждения данных.
Отладка (ОТРЕДАКТИРОВАНО):
- Покопавшись еще немного, я обнаружил, что иногда через некоторое время одна из структур sk_buffer повреждена, и это может привести к тому, что программа будет делать то, чего не должна, и, таким образом, вызвать панику ядра.
- После еще некоторых поисков я обнаружил, что повреждение происходит после
skb_copy_to_linear_data
(что точно так же, какmemcpy
). Имейте в виду, что это повреждение не происходит после каждого вызоваskb_copy_to_linear_data
, но когда повреждение происходит, оно всегда происходит после вызоваskb_copy_to_linear_data
. - Когда происходит повреждение, это не происходит в
rx_q->rx_skbuff
текущей записи (rx_q->rx_skbuff[entry]
). Например, если мы выполнимskb_copy_to_linear_data
onrx_q->rx_skbuff[X]
, поврежденнаяsk_buff
структура будетrx_q->rx_skbuff[Y]
(где X не равно Y). - Кажется, что физический адрес
skb->data
(который был выделен непосредственно передskb_copy_to_linear_data
вызовом) имеет тот же физический адресrx_q->rx_skbuff[Y]->end
. Первое, что я подумал, это то, что, возможно, драйвер не знает, что rx_q-> rx_skbuff [Y] был выпущен, но когда происходит это столкновение, я вижу, что rx_q-> rx_skbuff [Y]-> users равно 1. Как это может быть, есть идеи? - Не уверен, проблема это или нет, но вот что я заметил:
rx_skbuffers выделяются в двух местах: один раз, когда драйвер инициализирован, он вызывает __netdev_alloc_skb_ip_align с GPF_KERNEL, и второй раз, если rx_skbuff уже установлен.освобожденный он вызывает netdev_alloc_skb_ip_align (который внутренне использует GPF_ATOMIC). Разве эти выделения skb не должны вызываться с помощью GPF_DMA ?
Код:
Вот часть кода, в которой происходит повреждение.
Полный код драйвера взят из основной строки ядра Linux 4.19, и его можно найти здесь . Я вставил здесь только часть между строками 3451-3474.
Кто-нибудь находит здесь неправильное поведение в отношении использования DMA-API?
skb = netdev_alloc_skb_ip_align(priv->dev,
frame_len);
if (unlikely(!skb)) {
if (net_ratelimit())
dev_warn(priv->device,
"packet droppedn");
priv->dev->stats.rx_dropped ;
continue;
}
dma_sync_single_for_cpu(priv->device,
rx_q->rx_skbuff_dma
[entry], frame_len,
DMA_FROM_DEVICE);
// Here I check if data has been corrupted (the answer is ALWAYS NO).
debug_check_data_corruption();
skb_copy_to_linear_data(skb,
rx_q->
rx_skbuff[entry]->data,
frame_len);
// Here I check again if data has been corrupted (the answer is SOMETIMES YES).
debug_check_data_corruption();
skb_put(skb, frame_len);
dma_sync_single_for_device(priv->device,
rx_q->rx_skbuff_dma
[entry], frame_len,
DMA_FROM_DEVICE);
Некоторые последние замечания:
- Я попытался запустить ядро с
CONFIG_DMA_API_DEBUG
включенным. Это не всегда срабатывает, но когда я сам обнаруживаю повреждение (с помощью функции отладки), иногда я вижу, что/sys/kernel/debug/dma-api/num_errors
оно увеличилось, а иногда я также получаю этот журнал:DMA-API: device driver tries to sync DMA memory it has not allocated [device address=0x000000006879f902] [size=61 bytes]
- Я также включил
CONFIG_DEBUG_KMEMLEAK
и сразу после того, как я обнаружил событие повреждения данных, я получаю этот журнал:kmemleak: 1 new suspected memory leaks (see /sys/kernel/debug/kmemleak)
, но я все еще не понимаю, какие подсказки он выдает, хотя, похоже, он взят из той же части кода, которую я вставил сюда (__netdev_alloc_skb
был вызван из__netdev_alloc_skb_ip_align
). Это то, что/sys/kernel/debug/kmemleak
отображает:
unreferenced object 0xe9ea52c0 (size 192):
comm "softirq", pid 0, jiffies 6171209 (age 32709.360s)
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 40 4d 2d ea ............@M-.
00 00 00 00 00 00 00 00 d4 83 7c b3 7a 87 7c b3 ..........|.z.|.
backtrace:
[<045ac811>] __netdev_alloc_skb 0x9f/0xdc
[<4f2b009a>] stmmac_napi_poll 0x89b/0xfc4
[<1dd85c70>] net_rx_action 0xd3/0x28c
[<1c60fabb>] __do_softirq 0xd5/0x27c
[<9e007b1d>] irq_exit 0x8f/0xc0
[<beb36a07>] __handle_domain_irq 0x49/0x84
[<67c17c88>] gic_handle_irq 0x39/0x68
[<e8f5dc30>] __irq_svc 0x65/0x94
[<075bc7c7>] down_read 0x8/0x3c
[<075bc7c7>] down_read 0x8/0x3c
[<790c6556>] get_user_pages_unlocked 0x49/0x13c
[<544d56e3>] get_futex_key 0x77/0x2e0
[<1fd5d0e9>] futex_wait_setup 0x3f/0x144
[<8bc86dff>] futex_wait 0xa1/0x198
[<b362fbc0>] do_futex 0xd3/0x9a8
[<46f336be>] sys_futex 0xcd/0x138
Комментарии:
1. Вы упомянули 4.9, но ссылались на 4.19. Это опечатка?
2. Моя ошибка, я имел в виду 4.19. Спасибо
3. Какая архитектура? Может ли это быть вмешательство в кэш процессора? См. elixir.bootlin.com/linux/v4.19.147/source/Documentation /…
4. Allwinner A20 (ARM Cortex-A7). Есть ли способ проверить, не связано ли это с помехами в кэше? Возможно, когда драйвер вызывает <dma_sync_single_for_cpu> , его следует вызывать не с размером <frame_len>, а с размером <dma_buf_sz> , который соответствует тому же размеру, который мы использовали в <dma_map_single> (из документации я не вижу, что нам нужно это делать).
5. Вы можете попробовать отправлять пакеты, полные известного шаблона. Затем посмотрите на поврежденные данные, чтобы увидеть, есть ли в них этот известный шаблон. Это скажет вам, что вы получаете DMAed-данные там, где их не должно быть. Проверьте адреса в первом вызове синхронизации, всегда ли они такими, какими должны быть? То же самое с длиной?