Решение проблемы с медленной записью на USB Flash drive

Довольно частой проблемой, встречающейся у пользователей linux, является проблема с записью на флешки.

Проблема заключается в том, что когда идёт запись на флешку, скорость очень низкая (сначала, когда пишет в кэш, всё хорошо, но потом она падает до ~500-700 кбайт/с и система начинает довольно сильно тормозить. Причем тормоза настолько сильные, что иногда иксы виснут намертво на несколько минут.

Как выяснилось эмпирически, это случается из-за переключения процессоров и блокировок при использовании общего блока памяти. Логично решение указать, чтобы процессоры не переключались при обработки прерываний, на которых находятся usb.

Сначала в биосе отключаем опцию usb legacy support, заходим в систему и смотрим какие прерывания используются usb, для этого делаем:

grep usb /proc/interrupts
21: 45801 9374917 IO-APIC-fasteoi ehci_hcd:usb2, HDA Intel
22: 1 28 IO-APIC-fasteoi ohci_hcd:usb4
23: 1827 188061 IO-APIC-fasteoi ehci_hcd:usb1, ohci_hcd:usb3

То есть, у нас используются прерывания 21,22,23
на каждое прерывание указывается на каком процессоре оно висит, за это отвечает параметр smp_affinity

cat /proc/irq/21/smp_affinity
3
cat /proc/irq/22/smp_affinity
3
cat /proc/irq/22/smp_affinity
3

Теперь, что это значит
3 в шестнадцатеричной системе = 00000000.00000011 в двоичной (так как ядро скомпилировано с поддержкой 16 процессоров)
то есть обрабатыватся на CPU0, CPU1
Если нам нужно указать, чтобы обработка шла только на CPU0, то нужно задать 00000000.00000001, то есть 1
Если же нужно указать, чтобы обработка шла только на CPU1, то нужно задать 00000000.00000010, то есть 2

Теперь укажем, что будем обрабатывать на CPU0 все прерывания с висящими на них usb, естественно, всё делать нужно под рутом

echo 1 > /proc/irq/21/smp_affinity
echo 1 > /proc/irq/22/smp_affinity
echo 1 > /proc/irq/23/smp_affinity

Так как прерывания могут быть разными, то нужно либо вручную их узнавать и указывать, или написать скрипт и добавить его в автозагрузку.

Собственно, вот скрипт, который проверит прерывания, на которых висят usb и указывает, какой процессор выполняет работу с ними. Нужно скопировать его в /usr/local/bin и засунуть его в загрузку системы (например, прописать /usr/local/bin/setusbwrite в /etc/init.d/usb-flash), а так же дать скрипту права на запуск.

#!/bin/sh

for interruption in `grep usb /proc/interrupts| awk '{print $1}'| sed -e 's/\://g'` ; do
echo "Setting 1 in /proc/irq/${interruption}/smp_affinity";
echo 1 > /proc/irq/${interruption}/smp_affinity;
done

Источник welinux.ru

Оцените блог: 
Средняя: 2.3 (141 оценка)