Одновременный прямой доступ к памяти пользователя

Учти это

Поток 1 в пользовательской программе:

buf = malloc(9000);
memset(buf, 0xee, 9000);
read(buf, 9000); //for example gives pages [part of 7, 8, 9, part of 10]

Поток 2 в пользовательской программе:

buf = malloc(9000); //for example gives pages [part of 4, 6, 5, part of 7]
memset(buf, 0xee, 9000);
read(buf, 9000);

Водитель прочитал:

get_user_pages();

//build dma sg list from pages
//...

//the platform demands a cachesync
for(all pages) {
    dma_cache_wback_inv();
}

//start dma and wait for it to be done
//...
wait_event_interruptible_timeout(); //blocks calling thread until dma done

for(all pages) {
    if(read) SetPageDirty();
    page_cache_release();
}

Обратите внимание, что страница 7 используется обоими переносами, и это было большой проблемой, иногда приводившей к неверным данным (0xee находится в конце одного буфера). Просто для ясности: два чтения выполняются на разных каналах прямого доступа к памяти, поэтому они могут выполняться одновременно.

Мое решение состояло в том, чтобы выровнять буферы по страницам в пользовательской программе, чтобы DMA с двумя драйверами никогда не делил части одной и той же страницы.

Интересно, есть ли другое решение для этого? Я также удивляюсь, почему именно это было большой проблемой.


person Ronnie    schedule 02.03.2012    source источник
comment
Это, вероятно, довольно специфично для платформы - требование аннулировать кеш предполагает, что вы работаете во встроенной системе. Были ли два буфера достаточно близкими, чтобы совместно использовать строку кэша, или в вашей платформе есть другие ограничения?   -  person Adrian Cox    schedule 02.03.2012
comment
Да, это ppc440ep, и буферы, вероятно, достаточно близки. Строка кеша составляет 32 байта, и я видел только 4-12 байтов сломанными/неизмененными. Могут ли в кеше существовать 2 разные версии одной и той же физической памяти? И когда я делаю wback в одном потоке, может ли он уничтожить данные для другого? Насколько мне известно, не учитываемых опечаток нет. А как насчет get_user_pages? Что происходит, когда он возвращает две разные версии одной и той же страницы? Если get_user_pages и page_cache_release из разных потоков чередуются.   -  person Ronnie    schedule 02.03.2012
comment
Я не совсем понимаю, что делает get_user_pages/page_cache_release, за исключением предоставления med физических адресов страниц. В этой системе нет дискового кеша или чего-то еще, только память и процессорный кеш.   -  person Ronnie    schedule 02.03.2012


Ответы (1)


Это ограничение вашего встроенного процессора и DMA, который не является согласованным с кешем. На высокопроизводительных чипах PowerPC эта проблема исчезает.

Ваши два буфера совместно используют строку кэша в точке их пересечения. В то время как один поток находится в драйвере, записывающем кеш в оперативную память, второй поток все еще находится в memset, заполняя строку кеша значением 0xee.

DMA 1 записывает ваши данные в ОЗУ, но процессор по-прежнему хранит грязную строку кэша для этих данных, содержащую 0xee. Когда второй поток записывает кэш, он помещает 0xee поверх данных, полученных от DMA1.

Решения:

  1. Кэш-выравнивание ваших буферов (самая высокая производительность).
  2. Используйте буферы отказов в драйвере ядра (наиболее совместимые с существующим кодом пользовательского пространства).

Здесь проблема не в get_user_pages(), а в оборудовании и времени.

person Adrian Cox    schedule 02.03.2012
comment
Я думаю, что вы правы в том, что это проблема с кешем, но я также думаю, что видел ошибки без использования memset, потому что до отладки этой проблемы не было memset... Но, возможно, чтение буфера после выполнения DMA 1 может сделать кеш считывает 0xee обратно в кеш до выполнения DMA 2? - person Ronnie; 02.03.2012
comment
malloc также будет касаться данных вокруг концов буферов для обслуживания кучи. Этого может быть достаточно. - person Adrian Cox; 02.03.2012
comment
Да, это звучит как объяснение. - person Ronnie; 02.03.2012
comment
Ваш ответ заставил меня задуматься еще больше ... и я понимаю, что для этого может быть второе действительное объяснение ... когда первый поток обрабатывает (читает) данные после выполнения DMA 1, он заставит процессор читать обратно 0xee, возможно, смешанный с Данные DMA 2 в кеш перед выполнением DMA 2 (что делает dma_cache_wback_inv() бесполезным для DMA 2). Потому что я видел неверные данные сразу после выполнения DMA, но затем волшебным образом позже они были правильными... Решение все то же - кэширование, выравнивающее данные (Для нас это не лучший вариант, чтобы удвоить используемую память и потребовать память). - person Ronnie; 05.03.2012